为何C#异步方法中MethodBase.GetCurrentMethod返回MoveNext而非实际方法名?
问题原因与解决办法
为什么获取到的是MoveNext而非MyMethod?
C#的async/await是编译器提供的语法糖,编译器会自动把异步方法转换成一个实现IAsyncStateMachine接口的状态机类。原异步方法的执行逻辑会被拆分到这个状态机类的MoveNext方法中运行。当你调用MethodBase.GetCurrentMethod()时,代码实际处于状态机的MoveNext执行上下文里,因此拿到的是这个自动生成方法的名称。
原MyMethod本身在编译后仅负责初始化状态机并启动执行,真正的业务逻辑代码已经被移到了MoveNext中,所以调试时看到的当前方法是MoveNext。
正确获取实际方法名的方案
方案一:使用nameof运算符(推荐)
这是编译期确定方法名的方式,性能高且可靠,完全避免运行时反射的问题:
private async Task<bool> MyMethod() { string methodName = nameof(MyMethod); Logger.LogInformation("Entering method {method}", methodName); // ... 其他代码 ... }
方案二:利用CallerMemberNameAttribute封装通用日志
如果需要封装通用的日志方法,可以用这个特性让编译器自动传入调用方的方法名,无需手动指定:
private void LogMethodEntry([System.Runtime.CompilerServices.CallerMemberName] string methodName = "") { Logger.LogInformation("Entering method {method}", methodName); } private async Task<bool> MyMethod() { LogMethodEntry(); // 编译器自动填入"MyMethod"作为参数 // ... 其他代码 ... }
方案三:通过反射从状态机反向获取原方法(不推荐)
如果必须在运行时动态获取,可通过反射读取状态机的特性来定位原方法,但这种方式性能较差,仅适合特殊场景:
private async Task<bool> MyMethod() { var currentRuntimeMethod = MethodBase.GetCurrentMethod()!; var stateMachineType = currentRuntimeMethod.DeclaringType; var asyncAttr = stateMachineType?.GetCustomAttribute<System.Runtime.CompilerServices.AsyncStateMachineAttribute>(); string methodName = currentRuntimeMethod.Name; if (asyncAttr != null) { var originalMethod = GetType().GetMethods(BindingFlags.Instance | BindingFlags.NonPublic) .FirstOrDefault(m => m.GetCustomAttribute<System.Runtime.CompilerServices.AsyncStateMachineAttribute>()?.StateMachineType == asyncAttr.StateMachineType); if (originalMethod != null) { methodName = originalMethod.Name; } } Logger.LogInformation("Entering method {method}", methodName); // ... 其他代码 ... }
内容的提问来源于stack exchange,提问作者Green Grasso Holm
相关产品推荐
相关产品推荐

