Lambda函数抛出异常时栈追踪名称相关问题咨询
Lambda异常栈追踪与编译器生成方法的常见疑问解答
当你在Lambda函数中抛出异常时,栈追踪里的编译器生成名称确实会让人困惑,比如你给出的这段代码:
public void Test() { Func<AnotherClass, bool> myLambda = (AnotherClass p) => { if (p != null) { throw new Exception("Exception in method"); } return true; }; AnotherClass ac = new AnotherClass(); var r = myLambda(ac); } public class AnotherClass { }
抛出异常后得到的栈追踪是:
"CSharpTests.exe Error: 0 : System.Exception: Exception in method at CSharpTests.MarketingEntityManager.<>c.
b__0_0(AnotherClass p) at CSharpTests.MarketingEntityManager.Test() at CSharpTests.DisplayClassTest.Test()"
下面针对你提出的三个问题逐一解答:
1. <><c.b__0_0>到底是什么?
这串名称是C#编译器自动生成的闭包类和对应方法的标识,拆解来看:
<>前缀是编译器用来标记「编译器生成的类型/成员」的特殊符号,目的是和你手动定义的代码区分开,避免命名冲突。c是这个生成的嵌套类的名称(如果Lambda捕获了外部变量,类名通常会是<>c__DisplayClass0_0这类格式;如果没有捕获变量,会简化为<>c)。b__0_0是类中对应Lambda逻辑的方法名,命名规则里的b代表"bound method",后面的数字是编译器用来区分同一类中不同Lambda的序号。
2. 为什么Lambda变量名myLambda没被用作生成方法名?
myLambda只是你在源代码中用来引用Lambda表达式的变量名,它和Lambda编译后实际生成的方法完全是两个概念:
- 编译器处理Lambda时,只关注Lambda的逻辑本身,不会将变量名关联到生成的方法名上——毕竟变量名可以被修改、复用,甚至多个变量引用同一个Lambda,编译器需要一套稳定、无冲突的内部规则来生成这些隐藏成员。
- 编译器生成的方法名是按照自身规范生成的,核心目的是保证唯一性,同时明确标识这是匿名函数生成的成员,所以不会采用用户定义的变量名。
3. DisplayName的位置在哪里?
这里的DisplayName如果指的是能关联到你定义的myLambda的友好名称,默认情况下不会出现在异常栈追踪里:
- 编译器生成的方法本身并没有绑定你定义的变量名作为DisplayName,栈追踪里只会显示编译器生成的方法标识。
- 如果你想在调试或反射中获取更友好的信息,只能通过额外手段:比如在代码中给Lambda添加注释、在调试器里查看变量引用关系,或者利用.NET Core/.NET 5+中的
System.Diagnostics相关API,但这些都无法直接替换栈追踪里的编译器生成名称。
简单总结:这种命名方式是C#编译器处理匿名函数(包括Lambda)的标准行为,目的是在不污染用户命名空间的前提下,实现Lambda的逻辑执行。
内容的提问来源于stack exchange,提问作者justromagod
相关产品推荐
相关产品推荐

