调试器步进if语句和lambda表达式

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

它似乎与该变量fooif语句内的lambda表达式中使用的事实有关.我已经在Visual Studio 2012和2013(专业版和终极版)上测试并重现了这一点.

为什么会发生这种情况的任何想法?

Eri*_*ert 9

推测你正在跳过闭包生成的评论是正确的.移动指令指针时,不保证C#程序有任何特定的行为.如果你这样做会伤害,不要这样做.

实际上这是一个小谎言.有保证.例如,您可以保证在可验证的程序中这样做不会破坏clr的内部数据结构.您可以保证这样做不会使堆栈错位.等等.但是,您的数据结构不能表达或暗示任何保证!您将指令指针移动到您的危险之中.


xvo*_*rsx 8

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.