Nhìn vào đầu ra ILDASM, có thể có một lời giải thích ở đây ...
.locals init ([0] class Test.Program/'<>c__DisplayClass1' 'CS$<>8__locals2',
[1] class [mscorlib]System.Exception exception,
[2] string[] CS$0$0000)
IL_0000: nop
.try
{
IL_0001: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
IL_0006: stloc.0
IL_0007: nop
IL_0008: ldloc.0
IL_0009: ldc.i4.1
IL_000a: newarr [mscorlib]System.String
IL_000f: stloc.2
IL_0010: ldloc.2
IL_0011: ldc.i4.0
IL_0012: ldstr "1"
IL_0017: stelem.ref
IL_0018: ldloc.2
IL_0019: stfld string[] Test.Program/'<>c__DisplayClass1'::one
IL_001e: ldc.i4.1
IL_001f: ldc.i4.1
IL_0020: call class [mscorlib]System.Collections.Generic.IEnumerable`1<int32> [System.Core]System.Linq.Enumerable::Range(int32,
int32)
IL_0025: ldloc.0
IL_0026: ldftn instance bool Test.Program/'<>c__DisplayClass1'::'<Main>b__0'(int32)
IL_002c: newobj instance void class [mscorlib]System.Func`2<int32,bool>::.ctor(object,
native int)
IL_0031: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Where<int32>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Func`2<!!0,bool>)
IL_0036: pop
IL_0037: nop
IL_0038: leave.s IL_004a
} // end .try
catch [mscorlib]System.Exception
{
Khi bạn kéo con trỏ thực hiện, bạn có nguy cơ làm hư hỏng các cuộc gọi stack. Điều này là do kéo con trỏ theo nghĩa đen bỏ qua các dòng đó. Khi chạy trong trình gỡ rối, sau khi nhấn F10, con trỏ dừng lại ở đầu của quy trình Main
, trước khi thử. Nếu bạn kéo con trỏ đến việc tạo ra các mảng, bạn đang bỏ qua dòng thú vị này:
IL_0001: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
nào tạo ra một thể hiện của lớp Program
. Lớp chương trình sau đó được sử dụng sau đây:
IL_0019: stfld string[] Test.Program/'<>c__DisplayClass1'::one
nào vì bạn đã bỏ qua, không tạo ra đối tượng đó, vì vậy bạn sẽ có được một NullReferenceException
khi chạy.
Tại sao mọi người không thể tái tạo điều này trên VS2012, tôi không chắc chắn. Có lẽ trình biên dịch xuất ra IL khác nhau, nhưng điều này là xa như tôi có thể đến với việc sử dụng VS2013 Ultimate và C# 4.5.
Điều thú vị đủ, khi bạn nhận xét ra try/catch, sự bắt đầu của chương trình trong IL trông như thế này:
.locals init ([0] class Test.Program/'<>c__DisplayClass1' 'CS$<>8__locals2',
[1] string[] CS$0$0000)
IL_0000: newobj instance void Test.Program/'<>c__DisplayClass1'::.ctor()
IL_0005: stloc.0
nào bạn sẽ nhìn thấy dòng đầu tiên trong các thói quen tạo ra các đối tượng Program
. Tại sao trình biên dịch quyết định đặt dòng đó bên trong try/catch vượt ra ngoài tôi.
EDIT
Đào sâu hơn một chút, thay đổi chương trình của bạn như thế này:
private static void Main(string[] args)
{
string[] one;
try
{
// 1. Hit F10 to step into debugging.
one = new string[] { "1" }; //2. Drag arrow to this
// 3. Hit f5.
Enumerable.Range(1, 1)
.Where(x => one.Contains(x.ToString()));
}
catch (Exception exception)
{
Console.Write("BOOM!");
}
}
Kết quả trong mã làm việc. Kiểm tra IL, bạn có thể thấy rằng việc tạo ra ví dụ đã được chuyển ra ngoài thử:
.locals init ([0] class [mscorlib]System.Exception exception,
[1] class [mscorlib]System.Func`2<int32,bool> 'CS$<>9__CachedAnonymousMethodDelegate1',
[2] class Test.Program/'<>c__DisplayClass2' 'CS$<>8__locals3',
[3] string[] CS$0$0000)
IL_0000: ldnull
IL_0001: stloc.1
IL_0002: newobj instance void Test.Program/'<>c__DisplayClass2'::.ctor()
IL_0007: stloc.2
IL_0008: nop
.try
{
Trình biên dịch là đủ tốt đẹp để di chuyển tạo ra các mảng chuỗi từ bên ngoài cố gắng để bên trong cố gắng, vì vậy bỏ qua dòng đó vẫn còn kết quả trong một đối tượng hợp lệ. Mã hoạt động, vì vậy tôi đoán rằng NullReferenceException
thực sự là trường hợp của lớp Program
.
ngoại lệ là "đối tượng tham chiếu không được đặt để một thể hiện của một đối tượng." – Robino
Bạn nên thêm câu hỏi đó vào câu hỏi chứ không phải trong nhận xét. – juharr
Không thể tái tạo. – Habib