2010-07-12 19 views
6

Gần đây tôi đang phát triển một phần mềm phân tích và hiển thị thông tin XML từ một trang web. Đủ đơn giản phải không?Tôi dường như đã rơi vào một số vấn đề lớn, lớn với NullReferenceExceptions

Tôi nhận được LOADS của NullReferenceExceptions. Ví dụ: phương pháp này:

private void SetUserFriends(List<Friend> list) 
{ 
    int x = 40; 
    int y = 3; 

    if (list != null) 
    { 
     foreach (Friend friend in list) 
     { 
      FriendControl control = new FriendControl(); 
      control.ID = friend.ID; 
      control.URL = friend.URL; 
      control.SetID(friend.ID); 
      control.SetName(friend.Name); 
      control.SetImage(friend.Photo); 

      control.Location = new Point(x, y); 
      panel2.Controls.Add(control); 

      y = y + control.Height + 4; 
     } 
    } 
} 

Tôi phải quấn một xấu xí như tội lỗi Nếu vòng lặp foreach thực sự để ngăn chặn ngoại lệ.

Tôi cảm thấy tôi chỉ đang đặt những chiếc áo lót trên một chiếc lốp phẳng thay vì thực sự khắc phục được sự cố. Có cách nào tôi có thể giải quyết vấn đề này không? Có lẽ một cuốn sách tôi nên đọc về các mẫu lập trình hoặc những gì không?

Thực sự, tôi bị mất. Tôi có thể hỏi những câu hỏi sai.

+8

Bạn nên xem mã * gọi * 'SetUserFriends'. Nếu bạn cho rằng danh sách bạn bè không nên là 'null' (đó là một giả định đủ công bằng, tôi sẽ nói), thì lỗi là trong bất cứ điều gì đang truyền * trong *' null'. Sử dụng trình gỡ rối để tra cứu ngăn xếp cuộc gọi khi bạn nhận được ngoại lệ. –

+1

Kiểm tra tốt hơn lý do tại sao bạn có tham chiếu Danh sách trống thay vì đối tượng Danh sách trống. – BenV

+3

Đây là một lưu ý phụ, nhưng tôi muốn tranh luận về việc chấp nhận IEnumerable , để phương thức này không yêu cầu người gọi sử dụng một lớp thu thập cụ thể. –

Trả lời

15

Có vẻ như bạn không chắc chắn nên làm gì nếu bạn nhận được thông số xấu trong các phương pháp của mình. Không có gì sai với những gì bạn đang làm bây giờ, nhưng mẫu phổ biến hơn là kiểm tra các thông số trong phần đầu phương pháp của bạn, ném ngoại lệ nếu chúng không phải là những gì bạn mong đợi:

if (list == null) 
{ 
    throw new ArgumentNullException(list); 
} 

là một mẫu lập trình phòng thủ phổ biến - hãy kiểm tra để đảm bảo rằng dữ liệu bạn cung cấp vượt qua các kiểm tra độ chính xác cơ bản.

Bây giờ, nếu bạn đang gọi phương thức này một cách rõ ràng, và bạn đang tìm phương pháp này nhận được tham số rỗng list khi bạn không mong đợi nó, đã đến lúc xem logic của phương thức gọi. Bản thân tôi, tôi thích để vượt qua một danh sách trống khi tôi không có yếu tố, như trái ngược với null, để tránh các trường hợp đặc biệt như thế này.

+0

+1 Nếu bạn làm điều này một cách nhất quán, bạn sẽ học bằng cách làm thế nào để viết mã tránh được các giá trị vô ý. –

+1

+1 cho lập trình phòng thủ –

4

Tôi có lẽ sẽ để downvoted bởi "không có lối ra nhiều" đám đông nhưng tôi thường xử lý rằng với một kiểm tra đơn giản ngay từ đầu của phương pháp này:

if (list == null || list.Count == 0) return; 

này quy định cụ thể các điều kiện xuất cảnh, thì bạn không cần phải lo lắng về nhiều mức độ thụt đầu dòng trong phương thức của mình. Điều này chỉ hoạt động nếu bạn có thể đủ khả năng để nuốt thực tế là danh sách của bạn là rỗng hoặc trống - điều này có thể xảy ra trong một số trường hợp.

Nhưng tôi đồng ý với codeka, trong đó bạn cần phải xem mã gọi điện thoại và làm việc ra nếu bạn có thể cải thiện nó từ đó.

+4

Cách tiếp cận này * có thể * hoạt động cho trường hợp cụ thể này, nhưng nói chung nó dẫn đến các lỗi rất tinh vi. Hầu hết thời gian chúng tôi không thể suy luận hợp lý những gì người gọi dự định bằng cách chuyển sang 'null', vì vậy, an toàn nhất là hủy bỏ một ngoại lệ. –

+2

Cần phải ghi lại liệu một phương thức có chấp nhận null hay không và lý tưởng là nó sẽ không đáp ứng được điều kiện tiên quyết này. Tôi đồng ý với @Rex rằng lợi nhuận im lặng thường có thể làm tổn thương gỡ lỗi. –

+0

Tôi hoàn toàn đồng ý với bạn cả hai, nhưng có những trường hợp nó có thể hữu ích –

0

Tôi sẽ trả lại sớm (hoặc ném một InvalidArgumentException sớm) khi được nhập không hợp lệ.

Ví dụ:

private void SetUserFriends(List<Friend> list) 
{ 
    if (list == null) 
     return; 

    /* Do stuff */ 
} 

Hoặc bạn có thể sử dụng mô hình rỗng chung coalescing:

private void SetUserFriends(List<Friend> list) 
{ 
    list = list ?? new List<Friend>(); 

    /* Do Stuff */ 
} 
+1

Đề xuất kết hợp không có chút ít nực cười đối với kịch bản này. –

+1

Quay trở lại sớm và ném là * cực kỳ * cách tiếp cận khác nhau. Bạn đề nghị điều gì? –

+0

Uhm, nếu bạn sắp ném một ngoại lệ, cái đúng sẽ là 'ArgumentNullException', như ví dụ của Michael cho thấy. –

1

Cũng như ném ngoại lệ ArgumentNullException còn là một cái gì đó gọi là "Null Obejct mẫu" mà bạn có thể sử dụng nếu bạn muốn để chuyển xung quanh một giá trị rỗng, để cho biết, ví dụ: một cái gì đó không tồn tại, nhưng không muốn phải kiểm tra rõ ràng các giá trị rỗng. Về cơ bản nó là một lớp sơ khai thực hiện cùng một giao diện, nhưng các phương thức của nó thường hoặc là rỗng hoặc trả lại vừa đủ để làm cho chúng biên dịch. http://en.wikipedia.org/wiki/Null_Object_pattern

Cũng hữu ích cho các loại giá trị không thể thể hiện dễ dàng sự tồn tại của chúng, không thể rỗng.

+0

Thú vị, nhưng tôi không chắc chắn nếu nó áp dụng ở đây, là điều gần nhất với mẫu đối tượng null ở đây sẽ được giữ một danh sách trống xung quanh. Vấn đề khác, mà tôi đã chỉ ra ở nơi khác, là phương pháp này có lẽ nên chấp nhận một IEnumerable thay vì một danh sách. –

+0

Đúng, nhưng ông đã đề cập rằng đây chỉ là một ví dụ về "LOADS of NullReferenceExceptions" của ông. Nó có thể là giải pháp phù hợp cho một số người khác của anh ấy. Đối với điều này tôi sẽ ném ngoại lệ là tốt. – Spike

+0

Ấn tượng của tôi ở đây là đây không phải là vấn đề của việc quên để kiểm tra null và nhiều hơn nữa là không có bất kỳ ý tưởng nào tại sao nó lại là null ngay từ đầu. Mục đích của mẫu đối tượng null là để tránh việc kiểm tra null, nhưng nó sẽ không cung cấp bất kỳ thông tin chi tiết nào về vấn đề sâu hơn ở đây. Tuy nhiên, ngoại lệ, bởi vì chúng sẽ hạn chế việc truyền các giá trị rỗng, giúp dễ dàng theo dõi dấu vết ngăn xếp đến nơi mà không có dấu gạch ngang. –

2

Dường như lập trình phòng thủ và xác thực thông số là những gì bạn đang tìm kiếm.

Như những người khác đã nói, đơn giản xác nhận tham số sẽ làm việc cho bạn:

if (list == null) 
    throw new ArgumentNullException("list"); 

Ngoài ra, nếu bạn mệt mỏi với việc không ngừng viết séc như thế này cho mỗi tham số, bạn có thể kiểm tra một trong nhiều mã nguồn mở. Thư viện thực thi điều kiện tiên quyết NET. Tôi thích CuttingEdge.Conditions.

Bằng cách đó, bạn có thể sử dụng một cái gì đó như thế này:

Condition.Requires(list, "list").IsNotNull(); 

Tuy nhiên, việc thiết lập một điều kiện tiên quyết như một trong hai điều trên sẽ chỉ xác định rằng phương pháp của bạn không chấp nhận null. Vấn đề của bạn sẽ vẫn tồn tại ở chỗ bạn chuyển null vào phương thức! Để khắc phục điều đó, bạn sẽ phải kiểm tra những gì đang gọi phương pháp của bạn, và làm việc tại sao các đối tượng null đang được truyền vào.

+0

+1 để tập trung vào nguyên nhân gốc rễ. –

+1

Và +1 để tham khảo CuttingEdge.Conditions ;-) – Steven

0

Bạn thực sự đang đặt câu hỏi sai. Câu hỏi đúng là "không null đại diện cho một đầu vào không hợp lệ hoặc một lá cờ có nghĩa là X".

Cho đến khi loại tham chiếu không rỗng được thêm vào ngôn ngữ và thực hiện theo nhiều cách khác nhau của API, bạn có lựa chọn làm rõ ràng trong mã hoặc cho phép ngoại lệ tham chiếu null giúp bạn tìm được nơi mong đợi bị vi phạm và sau đó sửa dữ liệu/mã một cách này hay cách khác.

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