2012-04-28 33 views
5

Tìm kiếm một số hướng dẫn thực hành tốt nhất. Hãy nói rằng tôi có một dòng mã như thế này:Cách kiểm tra null trong các tham chiếu lồng nhau

Color color = someOrder.Customer.LastOrder.Product.Color; 

nơi khách hàng, LastOrder, sản phẩm, và màu sắc có thể là null dưới điều kiện bình thường. Tôi muốn màu sắc là null nếu bất kỳ một trong các đối tượng trong đường dẫn là null, tuy nhiên; để tránh các ngoại lệ tham chiếu null, tôi cần phải kiểm tra điều kiện rỗng cho từng đối tượng, ví dụ:

Color color = someOrder == null || 
       someOrder.Customer == null || 
       someOrder.Customer.LastOrder == null || 
       someOrder.Customer.Product == null ? 
       null : someOrder.Customer.LastOrder.Product.Color; 

hoặc tôi có thể làm điều này

Color color = null; 
try {color = someOrder.Customer.LastOrder.Product.Color} 
catch (NullReferenceException) {} 

Phương pháp đầu tiên làm việc rõ ràng, nhưng có vẻ như tẻ nhạt hơn một chút để mã và khó khăn hơn để đọc. Cách thứ hai là một chút dễ dàng hơn nhưng có lẽ không phải là một ý tưởng tốt để sử dụng xử lý ngoại lệ cho việc này.

Có cách nào khác để kiểm tra các giá trị rỗng và gán null cho màu nếu cần thiết không? Hoặc bất kỳ suy nghĩ về làm thế nào để tránh NullReferenceExceptions khi sử dụng tài liệu tham khảo lồng nhau?

+2

thể trùng lặp của (http [Sâu Null kiểm tra, là có một cách tốt hơn?]: // stackoverflow .com/question/2080647/sâu-null-kiểm tra-là-có-một-tốt hơn-way) –

+0

@MarkByers có, cảm ơn cho ref cho oth câu hỏi er. –

Trả lời

5

Bạn đang tìm kiếm toán tử dereferencing không an toàn.

Color color = someOrder?.Customer?.LastOrder?.Product?.Color; 

Rất tiếc, C# không hỗ trợ. Có lẽ nó sẽ được thêm vào sau, nhưng không có kế hoạch để làm điều đó vào lúc này.

liên quan

+4

cập nhật năm 2014, C# 6 hỗ trợ nó ngay bây giờ. –

+0

Bây giờ được hỗ trợ http://stackoverflow.com/a/2081709/1659248 –

0

Tôi chắc chắn sẽ thích phương pháp đầu tiên ... thứ hai khai thác các cơ chế ngoại lệ cho lưu lượng chương trình đó là thực tế xấu IMHO ...

AFAIK không có phím tắt hoặc "toán tử dereferencing không an toàn" trong C#.

0

Xác định phương pháp duy nhất để truy cập các thuộc tính lồng nhau. Ví dụ như thế này

private Customoer GetCustomer(Order order) 
{ 
    return order != null ? order.Customer : null; 
} 

private Order GetLastOrder(Customer customer) 
{ 
    return customer != null ? customer.LastOrder : null; 
} 

Sử dụng truy cập phương pháp định nghĩa thuộc tính của bạn trên ứng dụng

1

Thực hành tốt nhất là làm theo Law of Demeter mà âm thanh như: không nói chuyện với người lạ. I E. đối tượng nên tránh gọi các phương thức của đối tượng thành viên được trả về bởi phương thức khác. Điều này cho phép viết ít kết hợp, mã dễ bảo trì hơn và dễ đọc hơn.

Do đó, tránh sử dụng 'xác tàu' như someOrder.Customer.LastOrder.Product.Color, vì chúng vi phạm Luật Demeter. Nó thậm chí còn khó để hiểu những gì kinh doanh có nghĩa là mã này có. Tại sao bạn nhận được màu sắc của sản phẩm của một số thứ tự khác, mà không phải là hiện tại?

Cách có thể để loại bỏ đào tạo xác tàu - đẩy chức năng gần đến cuối thú vị của xác tàu. Trong trường hợp của bạn, hãy cân nhắc chuyển sản phẩm cuối cùng đến phương pháp của bạn, thay vì sử dụng một số đơn đặt hàng.

+0

Cảm ơn bạn. Tôi sẽ xem LoD. Nhân tiện, đoạn mã này chỉ là một ví dụ mà tôi tạo ra - không có ý nghĩa kinh doanh. –

+1

Tôi thích rằng ai đó đã nói điều này mặc dù nó không trả lời TRỰC TIẾP câu hỏi. Không có câu hỏi mà bạn phải viết mã phức tạp để đảm bảo rằng bạn không kết thúc cố gắng sử dụng một tham chiếu null trong mã như thế. Trong khi điều quan trọng là bạn biết câu trả lời kỹ thuật, bao gồm những gì C# có khả năng và không, loại mã này sẽ khiến bạn sợ hãi khi nhìn vào thiết kế tổng thể của bạn. –

1

nơi bạn cần đạt được điều này.

Cách sử dụng

Color color = someOrder.ComplexGet(x => x.Customer.LastOrder.Product.Color); 

hoặc

Color color = Complex.Get(() => someOrder.Customer.LastOrder.Product.Color); 

Helper Lớp Thực hiện

public static class Complex 
{ 
    public static T1 ComplexGet<T1, T2>(this T2 root, Func<T2, T1> func) 
    { 
     return Get(() => func(root)); 
    } 

    public static T Get<T>(Func<T> func) 
    { 
     try 
     { 
      return func(); 
     } 
     catch (Exception) 
     { 
      return default(T); 
     } 
    } 
} 
Các vấn đề liên quan