MoveNext而不是实际的方法/任务名称

使用log4net声明为:

private readonly ILog log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType()); 

在异步方法或任务中,如下所示:

 public async void CheckSomething() { log.Info(null); //.... } 

记录MoveNext而不是CheckSomething 。 知道如何让它记录一个实际的方法名称?

所有async方法都被重写到状态机中,以满足方法中潜在的await值。 代码所在的最终方法是MoveNext方法,这是log4net报告的方法。

在运行时没有很好的方法可以从MoveNext转换到最初编写代码的实际方法。 它们在元数据级别上有些断开连接。 您可能只需要直接记录名称

简短 :给定MoveNext()方法,试试这个:

 private static MethodBase GetRealMethodFromAsyncMethod(MethodBase asyncMethod) { var generatedType = asyncMethod.DeclaringType; var originalType = generatedType.DeclaringType; var matchingMethods = from methodInfo in originalType.GetMethods() let attr = methodInfo.GetCustomAttribute() where attr != null && attr.StateMachineType == generatedType select methodInfo; // If this throws, the async method scanning failed. var foundMethod = matchingMethods.Single(); return foundMethod; } 

长(免责声明)

不要在生产中使用它。 它依赖于编译器行为,这可能会在未来通知的情况下在将来的版本中发生变化。 关于编译器的以下假设是:

  1. 实际运行的异步方法是在生成的类型中生成的。
  2. 生成的类型是原始类型的嵌套类型,包含原始的手写方法。
  3. 原始方法获取编译器生成的属性AsyncStateMachine,其中提供了生成的类型。

它适用于我的代码,我只在调试/测试期间将其用于运行时代码分析。 请再次,请不要在生产代码中使用它

感谢JacekGorgoń的回答,这是我提出的实用工具。 它有一些改进,但仍然有很长的路要走很好的匿名或lambda方法。

 static string GetMethodContextName() { var name = new StackTrace().GetFrame(1).GetMethod().GetMethodContextName(); } static string GetMethodContextName(this MethodBase method) { if (method.DeclaringType.GetInterfaces().Any(i => i == typeof(IAsyncStateMachine))) { var generatedType = method.DeclaringType; var originalType = generatedType.DeclaringType; var foundMethod = originalType.GetMethods(Instance | Static | Public | NonPublic | DeclaredOnly) .Single(m => m.GetCustomAttribute()?.StateMachineType == generatedType); return foundMethod.DeclaringType.Name + "." + foundMethod.Name; } else { return method.DeclaringType.Name + "." + method.Name; } } 

这是一个示例用法:

 class Program { static void Main(string[] args) { // outputs Program.Main Console.WriteLine(GetMethodContextName()); Test().Wait(); } static async Task Test() { // outputs Program.Test Console.WriteLine(GetMethodContextName()); await Task.CompletedTask; } } 

我在log4net周围写了一个简单的包装器。

 public class Logger { private ILog _Log { get; set; } public Logger(Type declaringType) { _Log = LogManager.GetLogger(declaringType); } public void Error(Exception exception, [CallerMemberName] string callerMemberName = "") { _Log.Error(callerMemberName, exception); } } 

在执行日志记录的代码中,只需:

 private Logger Log = new Logger(MethodBase.GetCurrentMethod().DeclaringType); 

当然,如果你想做Info,Debug等事情,你可以将它添加到包装类中。

注意
这利用了c#5.0 [CallerMemberName]

用这个,效果很好……

 public void Log(Microsoft.Extensions.Logging.LogLevel level, string message, [System.Runtime.CompilerServices.CallerMemberName] string memberName = "", [System.Runtime.CompilerServices.CallerFilePath] string sourceFilePath = "", [System.Runtime.CompilerServices.CallerLineNumber] int sourceLineNumber = 0) { //do your logging here.... }