2015-06-12 11 views
7

Tại sao điều này xảy ra với BOOM?Hậu quả ngoài ý muốn khi thay đổi dòng thực thi tiếp theo trong Visual Studio

using System; 
using System.Linq; 

namespace Test 
{ 
    internal class Program 
    { 
     private static void Main(string[] args) 
     { 
      try 
      { 
       // 1. Hit F10 to step into debugging. 
       string[] one = {"1"}; //2. Drag arrow to make this next statement executed 
       // 3. Hit f5. 
       Enumerable.Range(1,1) 
        .Where(x => one.Contains(x.ToString())); 
      } 
      catch (Exception exception) 
      { 
       Console.Write("BOOM!"); 
      } 
     } 
    } 
} 
+0

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

+3

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

+0

Không thể tái tạo. – Habib

Trả lời

3

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.

+0

Tôi đã có nhiều phiên bản làm việc và không hoạt động của mã khi tôi đang chưng cất lỗi. Tôi chắc chắn sẽ sử dụng việc tháo gỡ để trả lời những câu hỏi này trong tương lai. – Robino

1

dài truyện ngắn khi bạn kéo vào mũi tên không có phân bổ bộ nhớ cho biến one nên về cơ bản tôi nghĩ rằng bạn đang nhận được một tham chiếu Null Pointer trong một wrapper khá

vui nghĩ là điều tương tự xảy ra trong. NET4.0, NET4.5, VS2013 và VS2015 RC được cho là có trình biên dịch khác (Roslyn) Có giao diện hình ảnh dưới đây

Lắp ráp của tôi khá tệ nên tôi sẽ không cố gắng hiểu mọi thứ điều đó đang diễn ra.

Bắt đầu ở đây

enter image description here

thực hiện bình thường

enter image description here

tôi đã nêu bật những thay đổi mảng của bạn là null nhưng nó tồn tại, cũng bạn sẽ nhìn thấy registry thay đổi.

Không có một cái nhìn vào những gì xảy ra khi tôi kéo

enter image description here

biến của bạn thậm chí không có (và cũng gần như nhìn vào những thay đổi registry), vì vậy tôi đoán rằng bạn đã chỉ cần bỏ qua một vài dòng hoặc lắp ráp.

Bây giờ bạn cũng có thể có một cái nhìn tại bộ nhớ và xem có gì ở đó cả.

Memory khi tôi bước máng

enter image description here

không gian rỗng nhưng nó ở đó.

Nếu tôi bước trough nó thậm chí còn có giá trị

enter image description here

Memory khi tôi kéo

enter image description here

Không có gì ở đó.

Xem xét thực tế là tôi đã thử với 2 phiên bản .NET và 2 trình biên dịch khác nhau, tôi nghĩ rằng đó phải là vấn đề với VisualStudio mà bạn có thể đăng lỗi này here nó có thể bị vá trong bản cập nhật trong tương lai.

Các vấn đề liên quan