When i use a variable in a linq expression inside a if statement that evaluates to false, and in debug mode drags execution pointer inside the If statement, i get a Null Ref exeption.
在 linq 表达式中使用int变量的时候,由于希望执行目标代码,所以拖动了执行断点,进入了if语句,但是赋值一直抛出异常: System.NullReferenceException: 未将对象引用设置到对象的实例。CS$<>8__locals0 是 null
Here is the code
using System.Collections.Generic;
using System.Linq;
namespace ErrorTest
{
class Program
{
static void Main(string[] args)
{
var theList = new List<TestData>() { new TestData { Id = 1, DataField = "nr one" }, new TestData { Id = 2, DataField = "nr two" } };
var value1 = 1;
var value2 = 2;
//set a break point att the if statement and drag debug pointer to row 16, so we end up inside the if statement but its false.
if (value1 == value2)
{
var thenr = 1;
var tt = theList.FirstOrDefault(x => x.Id == thenr);
}
}
}
//codebye.com CopyRight
class TestData
{
public int Id { get; set; }
public string DataField { get; set; }
}
}
Here is the IL generated
.method private hidebysig static void Main(string[] args) cil managed
{
.entrypoint
// Code size codebye.com CopyRight 122 (0x7a)
.maxstack 5
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class ErrorTest.TestData> theList,
[1] int32 value1,
[2] int32 value2,
[3] bool V_3,
[4] class ErrorTest.Program/'<>c__DisplayClass0_0' 'CS$<>8__locals0',
[5] class ErrorTest.TestData tt)
.language '{3F5162F8-07C6-11D3-9053-00C04FA302A1}', '{994B45C4-E6E9-11D2-903F-00C04FA302A1}', '{5A869D0B-6611-11D3-BD2A-0000F80849BD}'
// Source File 'C:\Users\ivanbaso\source\repos\CSConsoleApp6\CSConsoleApp6\Program.cs'
//000009: {
IL_0000: nop
//000010: var theList = new List<TestData>() { new TestData { Id = 1, DataField = "nr one" }, new TestData { Id = 2, DataField = "nr two" } };
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<class ErrorTest.TestData>::.ctor()
IL_0006: dup
IL_0007: newobj instance void ErrorTest.TestData::.ctor()
IL_000c: dup
IL_000d: ldc.i4.1
IL_000e: callvirt instance void ErrorTest.TestData::set_Id(int32)
IL_0013: nop
IL_0014: dup
IL_0015: ldstr "nr one"
IL_001a: callvirt instance void ErrorTest.TestData::set_DataField(string)
IL_001f: nop
IL_0020: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class ErrorTest.TestData>::Add(!0)
IL_0025: nop
IL_0026: dup
IL_0027: newobj instance void ErrorTest.TestData::.ctor()
IL_002c: dup
IL_002d: ldc.i4.2
IL_002e: callvirt instance void ErrorTest.TestData::set_Id(int32)
IL_0033: nop
IL_0034: dup
IL_0035: ldstr "nr two"
IL_003a: callvirt instance void ErrorTest.TestData::set_DataField(string)
IL_003f: nop
IL_0040: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class ErrorTest.TestData>::Add(!0)
IL_0045: nop
IL_0046: stloc.0
//000011: var value1 = 1;
IL_0047: ldc.i4.1
IL_0048: stloc.1
//000012: var value2 = 2;
IL_0049: ldc.i4.2
IL_004a: stloc.2
//000013: //set a break point att the if statement and drag debug pointer to row 16, so we end up inside the if statement but its false.
//000014: if (value1 == value2)
IL_004b: ldloc.1
IL_004c: ldloc.2
IL_004d: ceq
IL_004f: stloc.3
//000015: {
//000016: var thenr = 1;
//000017: var tt = theList.FirstOrDefault(x => x.Id == thenr);
//000018: }
//000019: }
//000020: }
//000021:
//000022: class TestData
//000023: {
//000024: public int Id { get; set; }
//000025: public string DataField { get; set; }
//000026: }
//000027: }
IL_0050: ldloc.3
IL_0051: brfalse.s IL_0079
IL_0053: newobj instance void ErrorTest.Program/'<>c__DisplayClass0_0'::.ctor()
IL_0058: stloc.s 'CS$<>8__locals0'
//000015: {
IL_005a: nop
//000016: var thenr = 1;
IL_005b: ldloc.s 'CS$<>8__locals0'
IL_005d: ldc.i4.1
IL_005e: stfld int32 ErrorTest.Program/'<>c__DisplayClass0_0'::thenr
//000017: var tt = theList.FirstOrDefault(x => x.Id == thenr);
IL_0063: ldloc.0
IL_0064: ldloc.s 'CS$<>8__locals0'
IL_0066: ldftn instance bool ErrorTest.Program/'<>c__DisplayClass0_0'::'<Main>b__0'(class ErrorTest.TestData)
IL_006c: newobj instance void class [mscorlib]System.Func`2<class ErrorTest.TestData,bool>::.ctor(object,
native int)
IL_0071: call !!0 [System.Core]System.Linq.Enumerable::FirstOrDefault<class ErrorTest.TestData>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Func`2<!!0,bool>)
IL_0076: stloc.s tt
//000018: }
IL_0078: nop
//000019: }
IL_0079: ret
} // codebye.com CopyRight end of method Program::Main
It seems that IL_005a: nop should be emitted on IL_0053
Answers :
Why do we think this is a compiler issue? The user here is essentially stepping past the closer initializing code. There isn’t much we can do to stop that in the compiler. Seems no different than say moving the cursor past the initialization of a local variable.
the sequence point that’s associated with {
should cover the closure initializer (i.e. be emitted at IL offset 0x53 instead of 0x5a), so that when the user moves the IP to {
the closure is initialized.
个人理解:这个异常不用处理,不手动拖动断点是不会触发异常的。