2008-09-22 34 views
28

Tôi chắc chắn rằng tất cả chúng ta đã nhận được sự mơ hồ tuyệt đối "Tham chiếu đối tượng không được đặt thành trường hợp ngoại lệ" trong một thời gian hay cách khác. Xác định đối tượng là vấn đề thường là một nhiệm vụ tẻ nhạt của việc thiết lập các điểm ngắt và kiểm tra tất cả các thành viên trong mỗi câu lệnh.Phát hiện đối tượng mục tiêu là gì khi NullReferenceException được ném

Có ai có bất kỳ thủ thuật nào để dễ dàng và hiệu quả xác định đối tượng gây ra ngoại lệ, hoặc thông qua các phương tiện chương trình hay không?

--chỉnh sửa

Có vẻ như tôi mơ hồ như ngoại lệ =). Vấn đề là _không phải gỡ lỗi ứng dụng để tìm đối tượng không đúng. Trình biên dịch/thời gian chạy không biết rằng đối tượng đã được cấp phát/khai báo và đối tượng đó chưa được khởi tạo. Có cách nào để trích xuất/xác định những chi tiết trong một ngoại lệ bắt

@ W. Craig Trader

lời giải thích của bạn mà nó là kết quả của một vấn đề thiết kế có lẽ là câu trả lời tốt nhất mà tôi có thể nhận được. Tôi khá cưỡng chế với mã hóa phòng thủ và đã quản lý để thoát khỏi hầu hết các lỗi này sau khi sửa thói quen của tôi theo thời gian. Những người còn lại chỉ cần tinh chỉnh tôi không kết thúc và dẫn tôi đăng câu hỏi này lên cộng đồng.

Cảm ơn các đề xuất của mọi người.

+0

Tôi không hiểu - nếu bạn đặt trình gỡ lỗi để phá vỡ NullReferenceExceptions, chắc chắn bạn có thể thấy biến nào gây ra lỗi tại thời điểm ngoại lệ được ném? – Grokys

Trả lời

16

Tại thời điểm NRE được ném, không có đối tượng mục tiêu - đó là điểm của ngoại lệ. Nhất bạn có thể hy vọng là để bẫy các tập tin và số dòng nơi ngoại lệ xảy ra. Nếu bạn đang gặp vấn đề xác định tham chiếu đối tượng nào đang gây ra sự cố, thì bạn có thể muốn suy nghĩ lại các tiêu chuẩn mã hóa của mình, vì có vẻ như bạn đang làm quá nhiều trên một dòng mã.

Giải pháp tốt hơn cho loại sự cố này là Design by Contract, thông qua cấu trúc ngôn ngữ dựng sẵn hoặc qua thư viện. DbC sẽ đề nghị kiểm tra trước bất kỳ đối số đầu vào nào cho một phương thức cho dữ liệu ngoài phạm vi (ví dụ: Null) và ném ngoại lệ vì phương thức này sẽ không hoạt động với dữ liệu xấu.

[Chỉnh sửa để phù hợp với câu hỏi chỉnh sửa:]

Tôi nghĩ rằng sự mô tả về TN & MT đang gây hiểu lầm bạn. Vấn đề mà CLR gặp phải là nó được yêu cầu dereference tham chiếu đối tượng, khi tham chiếu đối tượng là Null. Thực hiện chương trình ví dụ này:

public class NullPointerExample { 
    public static void Main() 
    { 
    Object foo; 
    System.Console.WriteLine(foo.ToString()); 
    } 
} 

Khi bạn chạy nó, nó sẽ ném NRE trên dòng 5, khi nó cố gắng đánh giá phương thức ToString() trên foo. Không có đối tượng để gỡ lỗi, chỉ là một tham chiếu đối tượng uninitialized (foo). Có một lớp và một phương pháp, nhưng không có đối tượng.


Re: Chris Marasti-Georg của answer:

Bạn không bao giờ nên ném TNMT mình - đó là một ngoại lệ hệ thống với một ý nghĩa cụ thể: CLR (hoặc JVM) đã nỗ lực để đánh giá một tham chiếu đối tượng mà không được khởi tạo. Nếu bạn kiểm tra trước tham chiếu đối tượng, hãy ném một số loại ngoại lệ đối số không hợp lệ hoặc ngoại lệ dành riêng cho ứng dụng, chứ không phải NRE, bởi vì bạn sẽ chỉ nhầm lẫn lập trình viên tiếp theo phải duy trì ứng dụng của bạn.

+1

+1 cho "làm quá nhiều trên một dòng mã" như tôi đã quyết định đó là của tôi vấn đề. – AaronLS

+0

Câu trả lời rất hữu ích, cảm ơn – Jack

+0

Tất cả những gì tôi muốn là từ "foo" (tên của tham chiếu đó là null trong ví dụ của bạn) trong đối tượng ngoại lệ ở đâu đó! Tại sao điều này quá khó? Nó là một chuỗi thẳng từ mã, tôi không cần đối tượng (như bạn đã đề cập không tồn tại), tôi chỉ cần chuỗi đơn giản đó! Trong khi DbC là một ý tưởng tuyệt vời, http://stackoverflow.com/a/116424/1739000 thực sự là một câu trả lời hữu ích hơn khi bạn gặp lỗi trước mặt bạn. –

1

Thực sự bạn không thể làm gì ngoài việc nhìn vào dấu vết ngăn xếp; nếu bạn đang dereferencing nhiều tham chiếu đối tượng trong cùng một dòng mã, không có cách nào để xác định cái nào là null mà không cần thiết lập một điểm ngắt. Bạn có thể tránh điều này bằng cách chỉ dereferencing một đối tượng trên mỗi dòng, nhưng điều đó sẽ dẫn đến một số mã trông khá khủng khiếp.

1

Vâng, bạn có thể không thực sự xác định các đối tượng như nó không tồn tại và do đó ngoại trừ bạn đang nhận được.

1

Dòng # và tệp thường là tất cả những gì bạn cần để tìm thủ phạm. Nếu bạn là người ném ngoại lệ, hãy cân nhắc sử dụng ArgumentNullException, nếu thích hợp hoặc kiểm tra các giá trị rỗng và ném NullReferenceException s có nhiều chi tiết hơn về trường rỗng.

Sửa @ chỉnh sửa của bạn :)

AFAIK, bạn sẽ phải kiểm tra chuỗi stack trace để nhận được rằng dòng # và tập tin. Đặt cược tốt nhất của bạn sẽ là nhận được ngoại lệ bên trong nhất, và sau đó nhìn vào dòng đầu tiên của dấu vết ngăn xếp của nó. Nếu bạn muốn có khả năng phân tích cú pháp thông tin đó để tìm ra trường nào gây ra null, và làm điều gì đó với tên của trường đó, tôi sợ bạn sẽ không may mắn.

@W. Craig Trader

Điểm tốt. Đối với một giá trị null được chuyển vào phương thức, cần xóa một số ArgumentNullException. Đối với một biến thành viên chưa được khởi tạo, một cái gì đó giống như một InvalidStateException có lẽ sẽ là tốt để ném. Thật không may, tôi không thể tìm thấy bất kỳ ngoại lệ như vậy trong MSDN. Cuộn của riêng bạn?

+0

Bạn có thể nghĩ đến 'InvalidOperationException' là khi' [...] một cuộc gọi phương thức không hợp lệ cho trạng thái hiện tại của đối tượng ' –

0

Nếu bạn đang bắt ngoại lệ đối với các thông báo người dùng thân thiện hoặc việc ghi nhật ký, bạn có thể muốn trình gỡ rối dừng lại ở ngoại lệ trong khi gỡ lỗi. Đi tới Gỡ lỗi/Ngoại lệ và kiểm tra các loại ngoại lệ bạn muốn trình gỡ lỗi ngừng chạy tại, System.NullReferenceException trong trường hợp của bạn.

0

Đặt VS để loại trừ ngoại lệ, sau đó khi bạn gặp lỗi, thường thì điều này khá rõ ràng. Cửa sổ theo dõi ngăn xếp sẽ cho bạn biết cách bạn đến đó. Không có gì khác bạn có thể làm ngoài việc đó.

0

Để tham khảo, một sợi tương tự: Should I catch exceptions only to log them?

điểm nổi bật là bạn muốn chụp một cách hiệu quả các ngoại lệ. Theo kinh nghiệm của tôi, mục đích là để đảm bảo rằng các lập trình viên kiểm tra các tham chiếu null trong mã - tuy nhiên chúng ta biết rằng trong thực tế, chúng ta bỏ lỡ một số. Mã UI phải có một số mức xử lý ngoại lệ. Tôi thích câu trả lời của tôi cho câu hỏi đó: My Answer. Quan trọng hơn, nhận xét của 1800 information, người chỉ ra rằng bạn chỉ cần ném, và không ném ex để nắm bắt toàn bộ ngăn xếp dấu vết đó là cách bạn cuối cùng gỡ lỗi những vấn đề này.

14

Như một vài câu trả lời đã chỉ ra, yêu cầu Visual Studio phá vỡ Throw for NullReferenceException.

Làm thế nào để nói với VS để phá vỡ khi ngoại lệ unhandled được ném

  • menu Debug | Trường hợp ngoại lệ (hoặc Ctrl +Alt +E)
  • khoan vào Common Language Runtime Exceptions
  • khoan vào hệ thống
  • Tìm System.NullRefernceException, và đánh dấu vào hộp để Phá vỡ bất cứ khi nào ngoại lệ này được ném, thay vì cho phép nó tiếp tục với bất kỳ khối Bắt nào được đặt tại vị trí

Vì vậy, bây giờ khi xảy ra, VS sẽ phá vỡ ngay lập tức và dòng Tuyên bố hiện tại sẽ nằm trên biểu thức được đánh giá là null.

cơ sở này rất hữu ích cho tất cả các loại ngoại lệ, bao gồm những tùy chỉnh (có thể thêm các loại tên đầy đủ, và VS sẽ phù hợp với nó vào gỡ lỗi thời gian)

Một nhược điểm để phương pháp này là nếu có mã được tải trong trình gỡ rối theo các hành động xấu của việc ném và bắt rất nhiều ngoại lệ bạn đang tìm kiếm, trong trường hợp nó quay trở lại thành vấn đề về cỏ khô (trừ khi bạn có thể sửa mã đó - sau đó bạn đã giải quyết xong hai vấn đề :)


Một mẹo khác có thể hữu ích (nhưng chỉ bằng một số ngôn ngữ) là việc sử dụng o f Khi (hoặc tương đương) từ khóa ... Trong VB, điều này có vẻ như

Try 
    ' // Do some work   ' 
Catch ex As Exception When CallMethodToInspectException(ex) 

End Try 

Bí quyết ở đây là sự biểu hiện Khi được đánh giá trước callstack là unwound vào khối Catch. Vì vậy, nếu bạn đang sử dụng trình gỡ lỗi, bạn có thể đặt một điểm ngắt biểu thức đó và nếu bạn nhìn vào cửa sổ gọi (Debug | Windows | Callstack), bạn có thể xem và điều hướng đến dòng đã kích hoạt ngoại lệ.

(Bạn có thể chọn trả về false từ CallMethodToInspectException, vì vậy khối catch sẽ bị bỏ qua và thời gian chạy sẽ tiếp tục tìm kiếm thông qua ngăn xếp cho khối catch thích hợp - có thể cho phép ghi nhật ký không ảnh hưởng đến hành vi, và với chi phí ít hơn một nắm bắt và tái ném)


Nếu bạn chỉ quan tâm đến khai thác gỗ không tương tác, sau đó giả sử bạn đã có một Debug xây dựng (hoặc một mức độ nào là bạn có làm đối phó với vấn đề tối ưu hóa, Phát hành bản phát hành với PDB), bạn có thể nhận được hầu hết thông tin cần thiết để theo dõi lỗi từ Ngoại lệ ToString, với số lượng dấu vết có chứa dấu vết.

Nếu số dòng không đủ, bạn cũng có thể lấy số cột (rất nhiều, địa phương hoặc biểu thức cụ thể là rỗng) bằng cách trích xuất StackTrace cho ngoại lệ (sử dụng kỹ thuật trên hoặc chỉ trong khối catch tự):

int colNumber = new System.Diagnostics.StackTrace(ex, true).GetFrame(0).GetFileColumnNumber(); 

trong khi tôi đã không nhìn thấy những gì nó làm cho NullReference hoặc thời gian chạy ngoại lệ phát sinh khác, cũng có thể quan tâm đến việc xem xét Exception Hunter như một công cụ phân tích tĩnh.

+0

Mỗi ngày tôi tìm hiểu một cái gì đó mới về cách mạnh mẽ công cụ gỡ lỗi trong VS là. Cảm ơn rất nhiều. –

+0

Cuối cùng sau một vài tuần phát triển các ứng dụng windows và tìm kiếm nhiều hơn một ngoại lệ mà không có dòng và lớp. Điều này sẽ phá vỡ nơi nó ném! Làm thế nào điều này được bỏ chọn theo mặc định! –

0

Liên quan đến thiết lập Visual Studio để bắt ngoại lệ (như được đề xuất here), KHÔNG QUÊN để xóa tùy chọn này khi bạn đã khắc phục sự cố. Tôi đã lãng phí nửa giờ cố gắng giải thích tại sao ứng dụng của tôi bị treo sâu trong một số phần của System.Windows.Forms ....

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