2012-04-12 38 views
5

Gần đây tôi đã có một lỗi mã hóa trong điều kiện nhất định, một biến không được khởi tạo và tôi đã nhận được một NullReferenceException. Điều này mất một thời gian để gỡ lỗi như tôi đã phải tìm các bit dữ liệu mà sẽ tạo ra điều này để tái tạo nó lỗi như ngoại lệ không cung cấp cho tên biến.Một cách tốt hơn để xử lý NullReferenceExceptions trong C#

Rõ ràng là tôi có thể kiểm tra mọi biến số trước khi sử dụng và đưa ra một ngoại lệ thông tin nhưng có cách nào tốt hơn (đọc ít mã hóa) hơn để làm điều này không? Một suy nghĩ khác mà tôi đã chuyển bằng các tệp pdb để thông tin lỗi có chứa dòng mã gây ra lỗi. Làm thế nào để những người khác tránh/xử lý vấn đề này?

Cảm ơn

+1

Luôn 'Tự do' cho giá trị null. – leppie

+0

@leppie - đó là rất nhiều khẳng định! Có, tôi có thể làm điều đó nhưng tôi đã hy vọng cho một giải pháp thanh lịch hơn để đưa vào các tình huống tài khoản như tôi quên làm điều đó :) –

+1

Protip: Giữ cho bạn phương pháp nhỏ (nói tối đa 10-20 dòng), sau đó bạn không thực sự cần số dòng . – leppie

Trả lời

11

Thứ nhất: đừng làm quá nhiều trong một câu lệnh. Nếu bạn có số lượng lớn các hoạt động dereferencing trong một dòng, nó sẽ là nhiều hơn khó tìm được thủ phạm. Các Law of Demeter giúp với điều này quá - nếu bạn đã có một cái gì đó như order.SalesClerk.Manager.Address.Street.Length sau đó bạn đã có rất nhiều tùy chọn để lội qua khi bạn nhận được một ngoại lệ. (Tôi không giáo điều về Luật của Demeter, nhưng tất cả mọi thứ trong chừng mực ...)

Thứ hai: thích đúc qua sử dụng as, trừ khi đó là hợp lệ cho đối tượng là một kiểu khác nhau, mà thông thường liên quan đến một kiểm tra null ngay sau đó. Vì vậy, ở đây:

// What if foo is actually a Control, but we expect it to be String? 
string text = foo as string; 
// Several lines later 
int length = text.Length; // Bang! 

Ở đây chúng ta sẽ nhận được một NullReferenceException và cuối cùng theo dõi nó trở lại text là null - nhưng sau đó bạn sẽ không biết liệu đó là bởi vì foo là null, hoặc bởi vì nó là một loại bất ngờ. Nếu nó nên thực sự, thực sự là mộtstring, sau đó đúc thay vì:

string text = (string) foo; 

Bây giờ bạn sẽ có thể cho biết sự khác nhau giữa hai kịch bản.

Thứ ba: như những người khác đã nói, xác thực dữ liệu của bạn - thường là đối số cho API công khai và tiềm năng nội bộ. Tôi làm điều này ở đủ nơi trong Noda Time rằng tôi đã có một lớp tiện ích để giúp tôi từ chối kiểm tra. Vì vậy, ví dụ (từ Period):

internal LocalInstant AddTo(LocalInstant localInstant, 
          CalendarSystem calendar, int scalar) 
{ 
    Preconditions.CheckNotNull(calendar, "calendar"); 
    ... 
} 

Bạn nên tài liệu những gì có thể và không thể được null, quá.

+0

yep, đó là những lời khuyên tốt. Tôi có nên vận chuyển với các tệp pdb để dòng được đưa ra không? Hiện tại mã sản xuất của tôi cung cấp tên phương thức nhưng không phải là dòng có thêm mức độ khó. –

+0

Cùng với 'không làm nhiều trên mỗi dòng', bạn có thể thêm 'không làm quá nhiều trong mỗi phương pháp'. Điều đó giúp giảm thiểu vấn đề. – Servy

+0

@directedbit: Nó phụ thuộc vào hoàn cảnh của bạn ... cho mã phía máy chủ, tuyệt đối. Nếu bạn đang vận chuyển mã phía máy khách, điều đó * có thể * nhạy cảm hơn hoặc lộn xộn ... –

2

Xin lỗi để nói rằng tôi sẽ luôn kiểm tra để xác minh rằng bất kỳ đối tượng nào tôi đang sử dụng trong một phương thức cụ thể không phải là rỗng.

Nó đơn giản như

if(this.SubObject == null) 
{ 
    throw new Exception("Could not perform METHOD - SubObject is null."); 
} 
else 
{ 
... 
} 

Nếu không tôi không thể nghĩ ra cách nào để được triệt để. Sẽ không có nhiều ý nghĩa với tôi để không thực hiện các kiểm tra này; Tôi cảm thấy đó là cách thực hành tốt.

+1

Tôi hy vọng bạn không chỉ ném Ngoại lệ ... –

+0

Không phải lúc nào. Tôi thường mở rộng ngoại lệ. Đây chỉ là một ví dụ. – DigitalJedi805

+2

Trong trường hợp này, bạn nên sử dụng InvalidOperationException nếu bản thân trạng thái hợp lệ - và ArgumentNullException để ngăn bạn không vào trạng thái đó nếu không. –

2

Trước hết, bạn nên luôn luôn xác thực thông tin nhập của bạn. Nếu không được phép null, hãy ném ArgumentNullException.

Bây giờ, tôi biết làm thế nào mà có thể gây đau đớn, vì vậy bạn có thể xem xét các công cụ viết lại lắp ráp làm điều đó cho bạn.Ý tưởng là bạn muốn có một loại thuộc tính đó sẽ đánh dấu những lập luận rằng không thể null:

public void Method([NotNull] string name) { ... 

Và Ổ ghi sẽ điền vào chỗ trống ...

Hoặc một phần mở rộng đơn giản phương pháp có thể giúp dễ dàng hơn

name.CheckNotNull(); 
+0

đó là lời khuyên tốt. Thật không may, đây là tất cả tôi. Tôi đã thất lạc một khung trong hàm để một biến được sử dụng ngoài phạm vi khởi tạo của nó. –

3

Rất nhiều trường hợp gần như không thể lập kế hoạch và giải thích cho mọi loại ngoại lệ có thể xảy ra tại bất kỳ điểm nào trong luồng thực thi của ứng dụng của bạn. Mã hóa phòng thủ chỉ có hiệu quả đối với một điểm nhất định. Bí quyết là có một ngăn chẩn đoán vững chắc được tích hợp vào ứng dụng của bạn có thể cung cấp cho bạn thông tin có ý nghĩa về các lỗi và sự cố không được giải quyết. Có trình xử lý cấp cao nhất (mương cuối cùng) ở cấp ứng dụng sẽ giúp ích rất nhiều cho điều đó.

Có, vận chuyển PDB (ngay cả với bản dựng bản phát hành) là cách tốt để có được dấu vết ngăn xếp hoàn chỉnh có thể xác định chính xác vị trí và nguyên nhân lỗi. Nhưng bất kỳ phương pháp chẩn đoán nào bạn chọn, nó cần phải được đưa vào thiết kế của ứng dụng để bắt đầu (lý tưởng). Retrofitting một ứng dụng hiện có có thể tẻ nhạt và tốn thời gian/tiền bạc.

+0

cảm ơn, có cách nào bạn khuyên bạn nên nướng nó. Hiện tại tôi có cách tiếp cận đơn giản để ghi nhật ký càng nhiều chi tiết càng tốt cho bất kỳ ngoại lệ chưa được xử lý nào. –

+0

Vấn đề là, nó phụ thuộc vào phương pháp/vị trí cụ thể ...đôi khi bạn muốn thông tin cụ thể về những gì đã xảy ra bởi vì bạn có thể mong đợi một số loại lỗi nhất định. Ở những người khác, như tôi đã nói, bạn có thể chỉ đơn giản là một tình huống bất ngờ. Điều đầu tiên bạn có thể làm là móc 'AppDomain.UnhandledException' (hoặc' Application_Error' trong global.asax cho các ứng dụng web), và sau đó bắt đầu trang bị thêm các phương thức riêng lẻ nếu cần. – kprobst

2

Nếu bạn chỉ là tìm kiếm một cách nhỏ gọn hơn để mã chống lại có tài liệu tham khảo null, không bỏ qua các nhà điều hành null-coalescing ??MSDN

Rõ ràng, nó phụ thuộc những gì bạn đang làm nhưng nó có thể được sử dụng để tránh thêm nếu phát biểu.

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