如何找到称为当前方法的方法?

发布于 2025-02-10 09:33:42 字数 196 浏览 2 评论 0 原文

登录C#时,如何学习称为当前方法的方法的名称?我对 System.Reflection.Methodbase.getCurrentMethod()了解全部了解,但是我想在堆栈跟踪中走一步。我已经考虑过解析堆栈跟踪,但是我希望找到一种更清洁的方法,例如 assembly.getCallingAssembly() ,但用于方法。

When logging in C#, how can I learn the name of the method that called the current method? I know all about System.Reflection.MethodBase.GetCurrentMethod(), but I want to go one step beneath this in the stack trace. I've considered parsing the stack trace, but I am hoping to find a cleaner more explicit way, something like Assembly.GetCallingAssembly() but for methods.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(17

不如归去 2025-02-17 09:33:42

尝试一下:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace(); 
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

单线:

(new System.Diagnostics.StackTrace()).GetFrame(1).GetMethod().Name

Try this:

using System.Diagnostics;
// Get call stack
StackTrace stackTrace = new StackTrace(); 
// Get calling method name
Console.WriteLine(stackTrace.GetFrame(1).GetMethod().Name);

one-liner:

(new System.Diagnostics.StackTrace()).GetFrame(1).GetMethod().Name
不如归去 2025-02-17 09:33:42

在C#5中,您可以使用 caller信息

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

您还可以获取 [CallerFilePath] [CallerlineNumber]

In C# 5, you can get that information using caller info:

//using System.Runtime.CompilerServices;
public void SendError(string Message, [CallerMemberName] string callerName = "") 
{ 
    Console.WriteLine(callerName + "called me."); 
} 

You can also get the [CallerFilePath] and [CallerLineNumber].

情感失落者 2025-02-17 09:33:42

您可以使用呼叫者信息和可选参数:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
    return memberName;
}

此测试说明了这一点:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo(nameof(Should_get_name_of_calling_method)));
}

虽然stacktrace的工作原理很快,并且在大多数情况下,呼叫者信息的速度仍然更快。在1000次迭代的样本中,我将其计入了40倍的速度。

You can use Caller Information and optional parameters:

public static string WhoseThere([CallerMemberName] string memberName = "")
{
    return memberName;
}

This test illustrates this:

[Test]
public void Should_get_name_of_calling_method()
{
    var methodName = CachingHelpers.WhoseThere();
    Assert.That(methodName, Is.EqualTo(nameof(Should_get_name_of_calling_method)));
}

While the StackTrace works quite fast above and would not be a performance issue in most cases the Caller Information is much faster still. In a sample of 1000 iterations, I clocked it as 40 times faster.

帅的被狗咬 2025-02-17 09:33:42

与速度比较的快速回顾是重要的部分。

档案/2013/07/25/c.net-little-tilter-getting-getting-caller-information.aspx

在compile time

static void Log(object message, 
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

使用堆栈确定呼叫者

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

两种方法的比较

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

因此,您会看到,使用属性要快得多!将近25倍
实际上,更快。

A quick recap of the 2 approaches with speed comparison being the important part.

http://geekswithblogs.net/BlackRabbitCoder/archive/2013/07/25/c.net-little-wonders-getting-caller-information.aspx

Determining the caller at compile-time

static void Log(object message, 
[CallerMemberName] string memberName = "",
[CallerFilePath] string fileName = "",
[CallerLineNumber] int lineNumber = 0)
{
    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, memberName, message);
}

Determining the caller using the stack

static void Log(object message)
{
    // frame 1, true for source info
    StackFrame frame = new StackFrame(1, true);
    var method = frame.GetMethod();
    var fileName = frame.GetFileName();
    var lineNumber = frame.GetFileLineNumber();

    // we'll just use a simple Console write for now    
    Console.WriteLine("{0}({1}):{2} - {3}", fileName, lineNumber, method.Name, message);
}

Comparison of the 2 approaches

Time for 1,000,000 iterations with Attributes: 196 ms
Time for 1,000,000 iterations with StackTrace: 5096 ms

So you see, using the attributes is much, much faster! Nearly 25x
faster in fact.

焚却相思 2025-02-17 09:33:42

我们可以通过仅实例化我们实际需要的框架而不是整个堆栈来改进阿萨德先生的代码(当前接受的答案):

new StackFrame(1).GetMethod().Name;

这可能会更好,尽管很可能仍然必须使用完整的堆栈创建该单一帧。此外,它仍然具有与Alex Lyman指出的相同的警告(优化器/本机代码可能会损坏结果)。最后,您可能需要检查以确保新的StackFrame(1) .getFrame(1)否返回 null ,as这种可能性似乎不太可能。

请参阅此相关问题:
您可以使用反射来找到当前执行方法的名称?

We can improve on Mr Assad's code (the current accepted answer) just a little bit by instantiating only the frame we actually need rather than the entire stack:

new StackFrame(1).GetMethod().Name;

This might perform a little better, though in all likelihood it still has to use the full stack to create that single frame. Also, it still has the same caveats that Alex Lyman pointed out (optimizer/native code might corrupt the results). Finally, you might want to check to be sure that new StackFrame(1) or .GetFrame(1) don't return null, as unlikely as that possibility might seem.

See this related question:
Can you use reflection to find the name of the currently executing method?

友欢 2025-02-17 09:33:42

通常,您可以使用 system.diarostics.diarostics.diarostics.stacktrace.stacktrace 类要获得 system.diagnostics.stackframe ,然后使用 getMethod() 获得 system.reflection.methodbase 对象。但是,有一些警告对这种方法

  1. :代表运行时堆栈 - 优化可能会嵌入方法,并且您将 不是 请参阅堆栈跟踪中的该方法。
  2. 它将 不是 显示任何本地框架,因此,如果您的方法通过本机方法调用,这将是 而不是 工作,并且目前没有可用的方法可以做到这一点。

注意:我只是在扩展答案 Firas Assad提供的答案)。

In general, you can use the System.Diagnostics.StackTrace class to get a System.Diagnostics.StackFrame, and then use the GetMethod() method to get a System.Reflection.MethodBase object. However, there are some caveats to this approach:

  1. It represents the runtime stack -- optimizations could inline a method, and you will not see that method in the stack trace.
  2. It will not show any native frames, so if there's even a chance your method is being called by a native method, this will not work, and there is in-fact no currently available way to do it.

(NOTE: I am just expanding on the answer provided by Firas Assad.)

遗失的美好 2025-02-17 09:33:42

As of .NET 4.5 you can use Caller Information Attributes:

  • CallerFilePath - The source file that called the function;
  • CallerLineNumber - Line of code that called the function;
  • CallerMemberName - Member that called the function.

    public void WriteLine(
        [CallerFilePath] string callerFilePath = "", 
        [CallerLineNumber] long callerLineNumber = 0,
        [CallerMemberName] string callerMember= "")
    {
        Debug.WriteLine(
            "Caller File Path: {0}, Caller Line Number: {1}, Caller Member: {2}", 
            callerFilePath,
            callerLineNumber,
            callerMember);
    }
    

 

This facility is also present in ".NET Core" and ".NET Standard".

References

  1. Microsoft - Caller Information (C#)
  2. Microsoft - CallerFilePathAttribute Class
  3. Microsoft - CallerLineNumberAttribute Class
  4. Microsoft - CallerMemberNameAttribute Class
调妓 2025-02-17 09:33:42

显然,这是一个较晚的答案,但是如果您可以使用.NET 4.5或更新的话,我有一个更好的选择:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

这将打印当前日期和时间,然后是“ namespace.classname.methodname”,然后以“:text”结尾。 br>
样本输出:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

样本使用:

Logger.WriteInformation<MainWindow>("MainWindow initialized");

Obviously this is a late answer, but I have a better option if you can use .NET 4.5 or newer:

internal static void WriteInformation<T>(string text, [CallerMemberName]string method = "")
{
    Console.WriteLine(DateTime.Now.ToString() + " => " + typeof(T).FullName + "." + method + ": " + text);
}

This will print the current Date and Time, followed by "Namespace.ClassName.MethodName" and ending with ": text".
Sample output:

6/17/2016 12:41:49 PM => WpfApplication.MainWindow..ctor: MainWindow initialized

Sample use:

Logger.WriteInformation<MainWindow>("MainWindow initialized");
窗影残 2025-02-17 09:33:42

请注意,由于优化,这样做在发行代码中是不可靠的。此外,以沙盒模式运行应用程序(网络共享)不允许您完全抓住堆栈框架。

考虑“ noreferrer”> tockent-opent-opiented编程(aop),例如 postsharp ,它没有从代码中调用,而是修改代码,从而知道始终在哪里。

Note that doing so will be unreliable in release code, due to optimization. Additionally, running the application in sandbox mode (network share) won't allow you to grab the stack frame at all.

Consider aspect-oriented programming (AOP), like PostSharp, which instead of being called from your code, modifies your code, and thus knows where it is at all times.

林空鹿饮溪 2025-02-17 09:33:42
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}
/// <summary>
/// Returns the call that occurred just before the "GetCallingMethod".
/// </summary>
public static string GetCallingMethod()
{
   return GetCallingMethod("GetCallingMethod");
}

/// <summary>
/// Returns the call that occurred just before the the method specified.
/// </summary>
/// <param name="MethodAfter">The named method to see what happened just before it was called. (case sensitive)</param>
/// <returns>The method name.</returns>
public static string GetCallingMethod(string MethodAfter)
{
   string str = "";
   try
   {
      StackTrace st = new StackTrace();
      StackFrame[] frames = st.GetFrames();
      for (int i = 0; i < st.FrameCount - 1; i++)
      {
         if (frames[i].GetMethod().Name.Equals(MethodAfter))
         {
            if (!frames[i + 1].GetMethod().Name.Equals(MethodAfter)) // ignores overloaded methods.
            {
               str = frames[i + 1].GetMethod().ReflectedType.FullName + "." + frames[i + 1].GetMethod().Name;
               break;
            }
         }
      }
   }
   catch (Exception) { ; }
   return str;
}
∞琼窗梦回ˉ 2025-02-17 09:33:42

也许您正在寻找这样的东西:

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name

Maybe you are looking for something like this:

StackFrame frame = new StackFrame(1);
frame.GetMethod().Name; //Gets the current method name

MethodBase method = frame.GetMethod();
method.DeclaringType.Name //Gets the current class name
年华零落成诗 2025-02-17 09:33:42
private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

一个很棒的课程在这里: http://www.csharp411.com/c-get-get-呼叫方法/

private static MethodBase GetCallingMethod()
{
  return new StackFrame(2, false).GetMethod();
}

private static Type GetCallingType()
{
  return new StackFrame(2, false).GetMethod().DeclaringType;
}

A fantastic class is here: http://www.csharp411.com/c-get-calling-method/

2025-02-17 09:33:42

要获得方法名称和班级名称,请尝试以下操作:

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }

For getting Method Name and Class Name try this:

    public static void Call()
    {
        StackTrace stackTrace = new StackTrace();

        var methodName = stackTrace.GetFrame(1).GetMethod();
        var className = methodName.DeclaringType.Name.ToString();

        Console.WriteLine(methodName.Name + "*****" + className );
    }
予囚 2025-02-17 09:33:42

我使用的另一种方法是将参数添加到所讨论的方法中。例如,代替 void foo(),使用 void foo(字符串上下文)。然后传递一些指示调用上下文的唯一字符串。

如果您只需要呼叫者/上下文进行开发,则可以在运输前删除 param

Another approach I have used is to add a parameter to the method in question. For example, instead of void Foo(), use void Foo(string context). Then pass in some unique string that indicates the calling context.

If you only need the caller/context for development, you can remove the param before shipping.

撑一把青伞 2025-02-17 09:33:42

额外的信息给firas assaad答案。

我已经使用新的stackframe(1).getMethod()。名称; in .net core 2.1带有依赖项注入,并且我将调用方法作为“ start”。

我尝试了 [System.Runtime.compilerServices.callermembername]字符串callername =“”
它给了我正确的呼叫方法

Extra information to Firas Assaad answer.

I have used new StackFrame(1).GetMethod().Name; in .net core 2.1 with dependency injection and I am getting calling method as 'Start'.

I tried with [System.Runtime.CompilerServices.CallerMemberName] string callerName = ""
and it gives me correct calling method

江湖正好 2025-02-17 09:33:42

我们还可以使用lambda的目的来找到呼叫者。

假设您有一种定义的方法:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

您想找到它的呼叫者。

1 。更改方法签名,以便我们具有类型动作的参数(func也将起作用):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2 。 lambda名称不是随机生成的。该规则似乎是:&gt; &lt; callermethodname&gt; __ x
callermethodname被以前的函数替换,而x是索引。

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1)
              );
    }

3 。当我们调用Methoda时,必须通过呼叫者方法生成操作/弹性参数。
示例:

MethodA(() => {});

4 。在Methoda内部,我们可以调用上面定义的辅助函数,并找到呼叫者方法的方法。

例子:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);

We can also use lambda's in order to find the caller.

Suppose you have a method defined by you:

public void MethodA()
    {
        /*
         * Method code here
         */
    }

and you want to find it's caller.

1. Change the method signature so we have a parameter of type Action (Func will also work):

public void MethodA(Action helperAction)
        {
            /*
             * Method code here
             */
        }

2. Lambda names are not generated randomly. The rule seems to be: > <CallerMethodName>__X
where CallerMethodName is replaced by the previous function and X is an index.

private MethodInfo GetCallingMethodInfo(string funcName)
    {
        return GetType().GetMethod(
              funcName.Substring(1,
                                funcName.IndexOf(">", 1, StringComparison.Ordinal) - 1)
              );
    }

3. When we call MethodA the Action/Func parameter has to be generated by the caller method.
Example:

MethodA(() => {});

4. Inside MethodA we can now call the helper function defined above and find the MethodInfo of the caller method.

Example:

MethodInfo callingMethodInfo = GetCallingMethodInfo(serverCall.Method.Name);
如痴如狂 2025-02-17 09:33:42
public static string GetCallerFullName<T>(this T callingObject,[CallerMemberName] string caller = default) =>$"{callingObject.GetType().Name}:{caller}";

这是对 Camilo Terevinto的解决方案的略有改进

this.GetCallerFullName();
public static string GetCallerFullName<T>(this T callingObject,[CallerMemberName] string caller = default) =>
quot;{callingObject.GetType().Name}:{caller}";

This is a slight improvement to Camilo Terevinto's solution because the calling convention is bit cleaner

this.GetCallerFullName();
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文