从异步函数中获取当前方法名称?

use*_*634 21 c# async-await

无论如何从异步函数中获取当前方法名称?

我试过了:

System.Reflection.MethodInfo.GetCurrentMethod();
Run Code Online (Sandbox Code Playgroud)

我尝试使用StackTrace和StrackFrame如下:

StackTrace strackTrace = new StackTrace();

for (int i = 0; i < strackTrace.GetFrames().Length; i++)
{
    SafeNativeMethods.EtwTraceInfo("Function" + i + ":" + function);
    SafeNativeMethods.EtwTraceInfo("Type" + i + ":" + strackTrace.GetFrame(i).GetType().Name);
    SafeNativeMethods.EtwTraceInfo("Method" + i + ":" + strackTrace.GetFrame(i).GetMethod().Name);
    SafeNativeMethods.EtwTraceInfo("ToString Call" + i + ":" + strackTrace.GetFrame(i).ToString());
}
Run Code Online (Sandbox Code Playgroud)

但它们似乎都不起作用,我会得到".ctor","InvokeMethod","Invoke","CreateInstance","CreateKnownObject"或"CreateUnknownObject"或"MoveNext"

有关如何做到这一点的任何想法?我想创建一个通用的记录器函数,我不想传入调用记录器函数的函数的名称,所以我尝试了stacktrace方法,没有用.

我放弃了,并说,好吧,我将传递函数名称作为第一个参数,但是当我从调用通用记录器函数的调用函数调用反射方法时,我总是得到".ctor"

有任何想法吗?注意我正在调用的通用记录器函数是同一个类中的静态方法(现在必须以这种方式...).

Mik*_*ray 17

C#5添加了来电者信息属性,可以为您提供更多您想要的内容.请注意,这些信息会在编译时将适当的信息插入到调用站点中,而不是使用运行时信息.功能更加有限(显然你无法获得完整的调用堆栈),但速度要快得多.

使用CallerMemberNameAttribute的示例:

using System.Runtime.CompilerServices;

public static void Main(string[] args)
{
    Test().Wait();            
}

private static async Task Test()
{
    await Task.Yield();
    Log();
    await Task.Yield();
}

private static void Log([CallerMemberName]string name = "")
{
    Console.WriteLine("Log: {0}", name);
}
Run Code Online (Sandbox Code Playgroud)

还有CallerFilePath和CallerLineNumber属性,可以获取有关呼叫站点的其他信息.

  • 使用调用者信息属性获取方法名称在全局错误记录器中是没有用的,因为您无法获取调用堆栈中引发异常的第一个方法。[CallerMemberName] 仅获取调用全局错误处理程序的方法的名称。 (2认同)

小智 9

  1. using System.Runtime.CompilerServices;

  2. GetMethodName在静态类文件 ( ) 中创建静态方法 ( ) ExtensionHelper

public static class ExtensionHelper 
{
    public static string GetMethodName([CallerMemberName] string name = "") => name;
}
Run Code Online (Sandbox Code Playgroud)
  1. 调用GetMethodName()以获取异步方法名称。

string methodName = ExtensionHelper.GetMethodName();


Avn*_*tan 8

而不是进行手动堆栈帧漫步,这既昂贵又有风险(因为版本构建可能会优化某些方法),您可以使用.NET 4.5中添加的CallerMemberNameAttribute一个Caller Information属性(您已经使用过,如果您使用async/await)这个确切的场景 - 传入记录器,属性更改处理程序等的成员名称.

它是这样的:

public void LogMessage(string message, [CallerMemberName] string caller = "")
{ 
    // caller should contain the name of the method that called LogMessage.
}
Run Code Online (Sandbox Code Playgroud)

我不知道这对async方法有任何限制.


小智 6

此方法适用于异步方法调用以及普通方法.(C#5)

/// <summary>
///     Returns Current method name
/// </summary>
/// <returns>callers method name</returns>
public string GetCurrentMethod([CallerMemberName] string callerName = "")
{
    return callerName;
}
Run Code Online (Sandbox Code Playgroud)


Nat*_*lch 2

您需要在异步方法的早期(第一个异步调用之前的某个位置)捕获方法名称。我发现跳过编译器生成的状态机的最方便方法是查看堆栈跟踪中每个方法的声明类型。

var method = new StackTrace()
    .GetFrames()
    .Select(frame => frame.GetMethod())
    .FirstOrDefault(item => item.DeclaringType == GetType());
await Task.Yield();
if (method != null)
{
    Console.WriteLine(method.Name);
}
Run Code Online (Sandbox Code Playgroud)