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

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

我试过了:

System.Reflection.MethodInfo.GetCurrentMethod(); 

我尝试使用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()); } 

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

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

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

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

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

使用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); } 

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

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

它是这样的:

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

我不知道这与async方法有任何限制。

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

 ///  /// Returns Current method name ///  /// callers method name public string GetCurrentMethod([CallerMemberName] string callerName = "") { return callerName; } 

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

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

我想回答你的问题有点晚了但是因为我遇到了同样的问题而我需要自己解决这个问题,因为在互联网上缺乏一个好的解决方案,这就是我所做的,它完美地运作于至少对我来说 –

  1. 在所有调用者都可以访问的地方定义以下Regex ,因为在使用它们之前需要解析Regex对象; 因此,它可能很昂贵,如果我们可以使用同一个,那么反复创建它们并不是一个好习惯。
    public static readonly Regex ASYNC_METHOD_NAME_FORMAT = new Regex(@"^\<(?\w+)>\w+?");
  2. 使用以下代码获取方法名称
    string methodName = ASYNC_METHOD_NAME_FORMAT.Match(MethodBase.GetCurrentMethod().ReflectedType.Name).Groups["method_name"].Value

我希望这有帮助!

你可以发送strackTrace.GetFrame(i).GetMethod()这是一个System.Reflection.MethodBase对象到一个函数,该函数检查System.Reflection.MethodBase.DeclaringType.FullName是否有<>字符,如果有的话将得到请求的方法名称位于<...>字符之间。

 static private string getMethodName(System.Reflection.MethodBase method) { string _methodName = method.DeclaringType.FullName; if (_methodName.Contains(">") || _methodName.Contains("<")) { _methodName = _methodName.Split('<', '>')[1]; } else { _methodName = method.Name; } return _methodName; } 

以及如何使用示例:

 var _stackTrace = new System.Diagnostics.StackTrace(exception, true); string _methodName = getMethodName(_stackTrace.GetFrame(0).GetMethod());