2014-12-30 14 views
13

Đọc rất nhiều về Null propagation operator ?., tôi thấy không có câu trả lời cho dù đó là hữu ích trong kịch bản sau đây.Null tuyên truyền nhà điều hành và foreach

Mã mà ném:

int[] values = null; 

foreach (var i in values) // Throws since values is null. 
{ 
    // ... 
} 

Để làm việc này, tôi có thêm một tấm séc null trước khi truy cập vào biến values.

Rất có thể mã trên nằm ngoài phạm vi của các cân nhắc thiết kế cho toán tử tuyên truyền Null. Tuy nhiên, để chắc chắn, tôi phải hỏi.

Câu hỏi của tôi:

là các nhà điều hành công tác tuyên truyền Null hữu ích khi cố gắng truy cập null bộ sưu tập trong một vòng lặp foreach?

+7

Không phải câu trả lời nhưng bạn có thể viết ' foreach (var i trong các giá trị ?? Enumerable.Empty ()) 'để tránh làm tổ. –

+0

Hoặc sử dụng ArrayList hoặc Danh sách thay vào đó :) – boctulus

+3

@Boctulus Đó là các loại tham chiếu không có giá trị, bạn biết không?!? –

Trả lời

7

Không, không. Nó được thiết kế để cho phép các thành viên truy cập của một đối tượng một cách an toàn. Trong trường hợp này, bạn phải kiểm tra xem mảng có phải là null không.

4

Bạn định sử dụng nó như thế nào?

Mã bạn cung cấp:

int[] values = null; 

foreach (var i in values) 
{ 
    // ... 
} 

enxpands vào một cái gì đó:

int[] values = null; 

var enumerator = values.GetEnumerator(); 
try 
{ 
    while (enumerator.MoveNext()) 
    { 
     var i = enumerator.Current; 
     // ... 
    } 
} 
finally 
{ 
    var disposable = enumerator as IDisposable; 
    if (disposable != null) 
    { 
     disposable.Dispose(); 
    } 
} 

Tôi đoán bạn có thể viết một cái gì đó như thế này:

int[] values = null; 

foreach (var i in values?.) 
{ 
    // ... 
} 

Trình biên dịch sẽ phải mở rộng nó một cái gì đó như thế này:

int[] values = null; 

var enumerator = values?.GetEnumerator(); 
try 
{ 
    while (enumerator?.MoveNext() ?? false) 
    { 
     var i = enumerator.Current; 
     // ... 
    } 
} 
finally 
{ 
    var disposable = enumerator as IDisposable; 
    if (disposable != null) 
    { 
     disposable.Dispose(); 
    } 
} 

Và có nhớ rằng:

a = b?.M(); 

mở rộng thành:

a = b == null ? null : b.M(); 

Nếu bạn muốn không viết một cách rõ ràng tuyên bố if, bạn luôn có thể dựa vào lợi ích cũ null-coalescing operator (??):

int[] values = null; 

foreach (var i in values ?? Enumerable.Empty<int>()) 
{ 
    // ... 
} 
+0

Giống như sau: http: // stackoverflow. com/a/31907661/7724 – bzlm

9

Tôi đã tìm được một cách làm việc khác:

Khi sử dụng (et al) tuyệt vời MoreLinq phần mở rộng của Jon Skeet, có một ForEach extension method mà tôi có thể sử dụng trong ví dụ ban đầu của tôi như:

int[] values = null; 

values?.ForEach(i=> /*...*/); // Does not throw, even values is null. 
1

Đối List<T> bạn có thể sử dụng list?.ForEach(i => ...); và cho enumerables khác mà bạn có thể làm cho mở rộng ForEach của riêng bạn như thế này:

public static void ForEach<T>(this IEnumerable<T> source, Action<T> action) { 

    if (source == null) { return; } 

    foreach (T item in source) { 
     action(item); 
    } 
} 

bạn gọi nó là như thế này: myPossiblyNullEnumerable.ForEach(i => ...);

Nếu bạn muốn tiện ích mở rộng ForEach của bạn bị ném khi được gọi cho số không trống, bạn có thể chỉ cần bỏ dấu trống, và gọi nó bằng cú pháp elvis giống như phiên bản của Danh sách: myPossiblyNullEnumerable?.ForEach(i => ...);

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