2010-08-26 43 views
6

Đây là loại bí truyền. Tôi chạy vào một NullReferenceException khi cố gắng mở một hình thức (trong thiết kế winforms) trong một dự án winforms trong visual studio 2008. Những điểm stack trace đến dòng thứ tư của đoạn mã sau:Tại sao '{' ném một NullReferenceException trong một phương thức tĩnh?

public static class Logger 
{ 
    public static void LogMethodEnter() 
    { 
     var frame = new StackFrame(1); 
     var method = frame.GetMethod(); 
     Trace.TraceInformation("{0}.{1}.{2}()", method.DeclaringType.Namespace, method.DeclaringType.Name, method.Name); 
     Trace.Indent(); 
    } 

    public static void LogMethodExit() 
    { 
     Trace.Unindent(); 
    } 
} 

... ý nghĩa dòng với dấu ngoặc nhọn mở. Tôi đã chạy vào cùng một vấn đề (nhưng không liên quan đến các nhà thiết kế winforms) trên các dự án khác, và tôi nghĩ rằng đó là một vấn đề liên quan đến luồng, nhưng tôi không có mã để tái tạo nó.

Tại sao điều này xảy ra và tại sao dấu vết ngăn xếp ngoại lệ trỏ vào đường thẳng bằng dấu ngoặc nhọn?

Làm rõ: Ngoại lệ tham chiếu null chỉ xảy ra trong trình thiết kế winforms. Khi ứng dụng được chạy, nó không ném lỗi đó.

+1

Các bạn đã thử nhìn vào tháo gỡ? Bạn có thể thấy những gì nó đang làm ở đó (mặc dù tôi đã không có nhiều thành công để nhận các biểu tượng để làm việc trong chế độ xem tháo gỡ). Ngoài ra còn có khả năng mỏng mà bạn đang chạy mã không khớp với nguồn của bạn. – Rup

+2

Bạn đã thử làm sạch giải pháp và xây dựng lại? – FrustratedWithFormsDesigner

+1

@Rup: Đồng ý về mã VS đang phàn nàn về việc không đồng bộ với tệp - nó có thể đang hoạt động với nội dung được lưu trong bộ nhớ cache? – FrustratedWithFormsDesigner

Trả lời

4

Tôi đoán rằng số dòng đang tắt (lý do thực tế cho điều đó là không quan trọng) và ngoại lệ được thực sự ném bởi biểu thức này:

method.DeclaringType.Namespace 

Và lý do bạn có thể thấy một NullReference ngoại lệ là vì biểu thức new StackFrame(1) một vài dòng trước đó đôi khi có thể trả về một khung trống. Khung trống có nghĩa là cuộc gọi tới .GetMethod() sẽ trả về giá trị rỗng và bạn sẽ chuyển sang chế độ này.

Lý do bạn đôi khi nhận được khung trống là trình biên dịch chỉ trong thời gian có thể chọn các phương thức ngắn, được gọi liên tục giống như phương thức trong mã của bạn. Điều đó sẽ ném ra khỏi ngăn xếp cuộc gọi của bạn để tốt nhất bạn nhận được một phương pháp cấp cao hơn bạn dự định, hoặc tồi tệ nhất (trong phương pháp chính của bạn) không có phương pháp cao hơn và bạn nhận được null.

+0

Thú vị. Vì vậy, điều đó không có nghĩa là ứng dụng sẽ ném ngoại lệ đó vào thời gian chạy? Tôi không thấy hành vi đó, tôi cho rằng tôi nên làm rõ rằng ngoại lệ CHỈ xảy ra khi tôi đang cố mở biểu mẫu trong nhà thiết kế winforms. –

+0

@Zach Tôi nghĩ rằng ngoại lệ là có thể trong thời gian chạy, nhưng bạn sẽ có khả năng không bao giờ nhìn thấy nó trong winforms bởi vì bạn không có khả năng sử dụng cuộc gọi này từ phương pháp chính ở trên cùng của ngăn xếp. Thay vào đó, bạn có thể thấy một số mục nhập nhật ký không chính xác ở những vị trí được inlined. Bạn thấy nó trong nhà thiết kế vì studio trực quan về cách visual studio chạy mã để tìm ra hành vi/ngoại hình của nhà thiết kế. Đột nhiên một cuộc gọi nội tuyến đang chạy ngay trên đầu ngăn xếp. –

+1

Cảm ơn sự thấu hiểu, tôi không biết về nội tuyến - Tôi sẽ thử thuộc tính [MethodImpl] và kiểm tra một số null. –

0

Việc trỏ đến một khung quăn/dòng mã dường như không chính xác đôi khi có thể xảy ra. Tôi nghĩ rằng nó chỉ đơn giản là ngoại lệ xảy ra trên dòng mã trước đó, và Visual Studio vì một số lý do làm nổi bật dòng tiếp theo.

Khi đoán, chương trình có thể không phá vỡ chính xác trên dòng nơi xảy ra ngoại lệ do bất kỳ số lượng yếu tố bên trong và bên ngoài nào.

Rất tiếc, tôi không thể giải thích rõ điều này.

+0

Visual Studio Làm nổi bật dòng tiếp theo khi quá trình thực thi vượt qua dòng trước đó nhưng vẫn chưa đạt đến dòng tiếp theo. Bạn hầu như sẽ thấy điều này khi Visual Studio làm nổi bật dòng màu xanh lục; có nghĩa là lỗi xảy ra bên trong phương thức được gọi bởi dòng trước đó. –

1

Tôi nghĩ rằng vấn đề có liên quan đến phương pháp tĩnh được gọi trước khi đối tượng tĩnh được xây dựng. Tôi đã khắc phục vấn đề trong dự án winforms bằng cách thêm static constructor.

Nếu tôi nhớ chính xác, hàm tạo tĩnh sẽ khóa toàn bộ đối tượng trong khi thực thi.

+0

Phương pháp của bạn có truy cập bất kỳ trường tĩnh nào của lớp không? –

+0

Không, những điều duy nhất mà phương thức sử dụng là một StackFrame và đối tượng Trace, không phải trong số đó là các trường tĩnh của lớp. –

+0

Và bất cứ điều gì khác trong lớp học của bạn? Tôi chỉ tò mò về lý do tại sao các nhà xây dựng tĩnh giải quyết vấn đề. Có vẻ như có thể vì việc thêm một hàm tạo tĩnh thay đổi hành vi làm thế nào một lớp tĩnh được khởi tạo. –

3

Có thể là .pdb tệp chứa thông tin về dòng đã lỗi thời.

Để khắc phục điều này, hãy xây dựng lại dự án của bạn và đảm bảo rằng việc tạo tệp .pdb được bật trong cài đặt dự án. Đối với C# các dự án này có thể được cấu hình trên Build tab bằng cách thiết lập nâng cao -> Debug Info hoặc là đầy đủ hoặc pdb chỉ.

+0

Đề nghị tốt, tôi đã chạy vào đó trước đây. Nhưng tôi đã thử điều đó rồi, không có hiệu lực. –

4

Đoán của tôi là bạn có một khởi tạo thành viên tĩnh ở đâu đó trong lớp học của bạn và trình khởi tạo đó ném một số NullReferenceException. Hơn nữa, tôi đoán bạn không có hàm tạo tĩnh, vì vậy đối tượng của bạn được đánh dấu là beforefieldinit và do đó, NullReferenceException được ném trong khi phương thức sử dụng nó là JITed.

Cái gì như:

public static class Logger 
{ 
    private static object x = InitObjectX(); 
    private static object InitObjectX() { 
     x.GetHashCode(); // Will throw since x is null. 
    } 

    public static void LogMethodEnter() 
    { 
     var frame = new StackFrame(1); 
     var method = frame.GetMethod(); 
     Trace.TraceInformation("{0}.{1}.{2}()", method.DeclaringType.Namespace, method.DeclaringType.Name, method.Name); 
     Trace.Indent(); 
    } 

    public static void LogMethodExit() 
    { 
     Trace.Unindent(); 
    } 
} 
+1

Tôi thích dự đoán này. –

+0

Hmm, có một vài trường tĩnh, nhưng chúng được khởi tạo như sau: static string Name = "xyz"; Điều đó có gây ra cùng một vấn đề không? –

+1

Tôi đã suy nghĩ giống nhau, nhưng một ngoại lệ trong quá trình khởi tạo một lớp tĩnh thường sẽ dẫn đến một 'TypeInitializationException' (với NRE là ngoại lệ bên trong). –

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