che*_*fly 7 c# lambda visual-studio-debugging
使用以下代码作为示例:
if (true)
{
string foo = null;
List<string> bar = new List<string>
{
"test"
};
bar.Any(t => t == foo);
}
Run Code Online (Sandbox Code Playgroud)
如果我以常规方式运行此程序(没有断点或任何其他中断),一切都可以正常运行,无异常或错误(正如您所期望的那样).
现在,如果我在if语句上放置一个断点并将光标移动到大括号,如下图所示(使用我的鼠标,不使用F10,所以跳过if(true)语句):

System.NullReferenceException调试器执行语句时,我得到类型的异常string foo = null
它似乎与该变量foo在if语句内的lambda表达式中使用的事实有关.我已经在Visual Studio 2012和2013(专业版和终极版)上测试并重现了这一点.
为什么会发生这种情况的任何想法?
推测你正在跳过闭包生成的评论是正确的.移动指令指针时,不保证C#程序有任何特定的行为.如果你这样做会伤害,不要这样做.
实际上这是一个小谎言.有保证.例如,您可以保证在可验证的程序中这样做不会破坏clr的内部数据结构.您可以保证这样做不会使堆栈错位.等等.但是,您的数据结构不能表达或暗示任何保证!您将指令指针移动到您的危险之中.
Eric的回答和评论已经描述了为什么它会发生.我想强调在这个特殊情况下发生的事情.
这是生成的IL:
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
.maxstack 3
.locals init (
[0] class [mscorlib]System.Collections.Generic.List`1<string> bar,
[1] class [mscorlib]System.Collections.Generic.List`1<string> <>g__initLocal0,
[2] class StackOverflow.Program/<>c__DisplayClass2 CS$<>8__locals3,
[3] bool CS$4$0000)
L_0000: nop
L_0001: ldc.i4.0
L_0002: stloc.3
L_0003: newobj instance void StackOverflow.Program/<>c__DisplayClass2::.ctor()
L_0008: stloc.2
L_0009: nop
L_000a: ldloc.2
L_000b: ldnull
L_000c: stfld string StackOverflow.Program/<>c__DisplayClass2::foo
L_0011: newobj instance void [mscorlib]System.Collections.Generic.List`1<string>::.ctor()
L_0016: stloc.1
L_0017: ldloc.1
L_0018: ldstr "test"
L_001d: callvirt instance void [mscorlib]System.Collections.Generic.List`1<string>::Add(!0)
L_0022: nop
L_0023: ldloc.1
L_0024: stloc.0
L_0025: ldloc.0
L_0026: ldloc.2
L_0027: ldftn instance bool StackOverflow.Program/<>c__DisplayClass2::<Main>b__1(string)
L_002d: newobj instance void [mscorlib]System.Func`2<string, bool>::.ctor(object, native int)
L_0032: call bool [System.Core]System.Linq.Enumerable::Any<string>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>, class [mscorlib]System.Func`2<!!0, bool>)
L_0037: pop
L_0038: nop
L_0039: ret
}
Run Code Online (Sandbox Code Playgroud)
注意L_0003行.它为自动生成的c__DisplayClass2类调用ctor ,它保存foo字段,因为你在lambda中使用它.因此NullReferenceException,因为您的跳过类初始化,然后您foo在一行上分配实例的字段L_000c.
太糟糕了,没有简单的方法来调试IL级别来验证这一点,但我们可以调试JITed程序(Debug - > Disassembly)
这是你的第一个断点:

然后光标移动后:

其中一个滑雪呼叫教练必须打电话给ctor L_0003.