Cập nhật: Bắt đầu với Visual Studio 2015, trình biên dịch C # (phiên bản ngôn ngữ 6) hiện nhận ra ?.
toán tử, giúp "kiểm tra null sâu" một cách dễ dàng. Xem câu trả lời này để biết chi tiết.
Ngoài việc thiết kế lại mã của bạn, như
câu trả lời đã xóa này được đề xuất, một tùy chọn khác (mặc dù khủng khiếp) sẽ là sử dụng một try…catch
khối để xem liệu có NullReferenceException
xảy ra đôi khi trong quá trình tra cứu thuộc tính sâu sắc đó không.
try
{
var x = cake.frosting.berries.loader;
...
}
catch (NullReferenceException ex)
{
// either one of cake, frosting, or berries was null
...
}
Cá nhân tôi sẽ không làm điều này vì những lý do sau:
- Nó trông không đẹp.
- Nó sử dụng xử lý ngoại lệ, nhằm vào các tình huống đặc biệt và không phải là điều mà bạn mong đợi sẽ xảy ra thường xuyên trong quá trình hoạt động bình thường.
NullReferenceException
Có lẽ không bao giờ nên bị bắt một cách rõ ràng. (Xem câu hỏi này .)
Vì vậy, có thể sử dụng một số phương thức mở rộng hay nó sẽ là một tính năng ngôn ngữ, [...]
Đây gần như chắc chắn phải là một tính năng ngôn ngữ (có sẵn trong C # 6 dưới dạng toán tử .?
và ?[]
toán tử), trừ khi C # đã có đánh giá lười biếng phức tạp hơn, hoặc trừ khi bạn muốn sử dụng phản xạ (có lẽ cũng không phải là một ý tưởng tốt cho lý do hiệu suất và loại an toàn).
Vì không có cách nào đơn giản để chuyển cake.frosting.berries.loader
đến một hàm (nó sẽ được đánh giá và đưa ra một ngoại lệ tham chiếu null), bạn sẽ phải thực hiện một phương thức tra cứu chung theo cách sau: Nó đưa vào một đối tượng và tên của các thuộc tính để tra cứu:
static object LookupProperty( object startingPoint, params string[] lookupChain )
{
// 1. if 'startingPoint' is null, return null, or throw an exception.
// 2. recursively look up one property/field after the other from 'lookupChain',
// using reflection.
// 3. if one lookup is not possible, return null, or throw an exception.
// 3. return the last property/field's value.
}
...
var x = LookupProperty( cake, "frosting", "berries", "loader" );
(Lưu ý: mã được chỉnh sửa.)
Bạn nhanh chóng thấy một số vấn đề với cách tiếp cận như vậy. Đầu tiên, bạn không nhận được bất kỳ loại an toàn nào và có thể có giá trị tài sản thuộc loại đơn giản. Thứ hai, bạn có thể quay lại null
nếu có sự cố xảy ra và bạn sẽ phải kiểm tra điều này trong chức năng gọi điện của mình hoặc bạn ném ngoại lệ và quay lại nơi bạn bắt đầu. Thứ ba, nó có thể chậm. Thứ tư, nó trông xấu hơn so với những gì bạn bắt đầu.
[...], Hay đó chỉ là một ý tưởng tồi?
Tôi sẽ ở lại với:
if (cake != null && cake.frosting != null && ...) ...
hoặc đi với câu trả lời trên của Mehrdad Afshari.
PS: Quay lại khi tôi viết câu trả lời này, rõ ràng tôi đã không xem xét các cây biểu thức cho các hàm lambda; xem ví dụ câu trả lời của @driis để biết giải pháp theo hướng này. Nó cũng dựa trên một loại phản xạ và do đó có thể không thực hiện tốt như một giải pháp đơn giản hơn ( if (… != null & … != null) …
), nhưng nó có thể được đánh giá đẹp hơn từ quan điểm cú pháp.