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

use*_*346 19 c# log4net methodbase async-await

使用log4net声明为:

private readonly ILog log = 
       LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType());
Run Code Online (Sandbox Code Playgroud)

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

public async void CheckSomething()
{
    log.Info(null);
    //....
}
Run Code Online (Sandbox Code Playgroud)

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

Jar*_*Par 22

将所有async方法重写到状态机中以满足await方法中的潜在值.代码存在的最终方法是报告的MoveNext方法log4net.

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

  • 要直接记录该名称,您可能需要使用C#5.0 [调用者信息参数](http://msdn.microsoft.com/en-us/library/hh534540.aspx). (14认同)

Jac*_*goń 9

简短:给出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<AsyncStateMachineAttribute>() 
        where attr != null && attr.StateMachineType == generatedType 
        select methodInfo;

    // If this throws, the async method scanning failed.
    var foundMethod = matchingMethods.Single();
    return foundMethod;
}
Run Code Online (Sandbox Code Playgroud)

长(免责声明)

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

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

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


Scu*_*eve 5

我围绕 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);
    }
}
Run Code Online (Sandbox Code Playgroud)

在进行日志记录的代码中,只需执行以下操作:

private Logger Log = new Logger(MethodBase.GetCurrentMethod().DeclaringType);
Run Code Online (Sandbox Code Playgroud)

当然,如果你想做信息、调试等事情,你可以将它添加到包装类中。

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


bbo*_*234 5

感谢 Jacek Gorgo? 的回答,这是我想出的实用程序。它有一些改进,但要与匿名或 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<AsyncStateMachineAttribute>()?.StateMachineType == generatedType);
        return foundMethod.DeclaringType.Name + "." + foundMethod.Name;
    } else {
        return method.DeclaringType.Name + "." + method.Name;
    }
}
Run Code Online (Sandbox Code Playgroud)

这是一个示例用法:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Ste*_*uck 5

用这个,效果很好...

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....
    }
Run Code Online (Sandbox Code Playgroud)