2011-12-20 36 views
49

Tôi biết danh sách rỗng thường là thích hơn NULL. Nhưng tôi sẽ trả về NULL, vì hai lý do chủ yếu làC# có IsNullOrEmpty cho Danh sách/IEnumerable?

  1. Tôi phải kiểm tra và xử lý giá trị null một cách rõ ràng, tránh lỗi và tấn công.
  2. Thật dễ dàng để thực hiện thao tác ?? sau đó để nhận giá trị trả lại.

Đối với chuỗi, chúng tôi có IsNullOrEmpty. Có bất cứ điều gì từ C# chính nó làm điều tương tự cho Danh sách hoặc IEnumerable?

+6

Không, nhưng thêm phương thức tiện ích là tầm thường. –

+0

bản sao có thể có của [Cách kiểm tra xem IEnumerable có rỗng hay không?] (Http://stackoverflow.com/questions/5047349/how-to-check-if-ienumerable-is-null-or-empty) – octothorpentine

Trả lời

54

gì nướng vào khuôn khổ, nhưng đó là một phương pháp mở rộng về phía trước khá đơn giản.

See here

/// <summary> 
    /// Determines whether the collection is null or contains no elements. 
    /// </summary> 
    /// <typeparam name="T">The IEnumerable type.</typeparam> 
    /// <param name="enumerable">The enumerable, which may be null or empty.</param> 
    /// <returns> 
    ///  <c>true</c> if the IEnumerable is null or empty; otherwise, <c>false</c>. 
    /// </returns> 
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable) 
    { 
     if (enumerable == null) 
     { 
      return true; 
     } 
     /* If this is a list, use the Count property for efficiency. 
     * The Count property is O(1) while IEnumerable.Count() is O(N). */ 
     var collection = enumerable as ICollection<T>; 
     if (collection != null) 
     { 
      return collection.Count < 1; 
     } 
     return !enumerable.Any(); 
    } 

Daniel Vaughan mất thêm bước đúc để ICollection (nếu có thể) vì lý do hiệu suất. Một cái gì đó tôi sẽ không có suy nghĩ để làm.

+2

Chú ý phải được thực hiện mặc dù rằng các cuộc gọi đến 'enumerable.Any()' có thể mất một yếu tố của một liệt kê không thể rewindable. Bạn có thể bọc nó vào thứ gì đó sẽ theo dõi nguyên tố đầu tiên đó (và xử lý null độc đáo hoặc chúng ta phủ nhận toàn bộ vấn đề của OP), nhưng nó có thể dễ dàng hơn trong một số trường hợp để kết hợp với một điều tra rỗng và chỉ sử dụng kết quả . –

+0

Uh, tôi có bị mất hoặc dòng cuối cùng của hàm đó là 'return! Enumerable.Any();'? Tôi sẽ chỉnh sửa nó. –

+1

Có nên thử đúc thành 'ICollection' không chung, vì một' IEnumerable 'có thể giống như một thể hiện của' Danh sách ', không thực hiện' ICollection 'nhưng thực thi' ICollection' không chung chung? – supercat

20

Không có gì được xây dựng tại là

Nó là một phương pháp mở rộng đơn giản mặc dù:.

public static bool IsNullOrEmpty<T>(this IEnumerable<T> enumerable) 
{ 
    if(enumerable == null) 
    return true; 

    return !enumerable.Any(); 
} 
+3

Bạn cần "không" trên cuộc gọi collection.Any(). –

+0

@ChuckBlumreich - Cảm ơn bạn đã sửa. – Oded

+0

Ngoài ra, tại sao bạn đặt tên bộ sưu tập là? tốt hơn nên đặt tên là enumerable. –

9
var nullOrEmpty = list == null || !list.Any(); 
1

Nếu bạn cần để có thể lấy tất cả các yếu tố trong trường hợp nó không phải là trống rỗng, sau đó một số các câu trả lời ở đây sẽ không làm việc, bởi vì các cuộc gọi đến Any() trên đếm được không rewindable sẽ "quên" một phần tử.

Bạn có thể mất một cách tiếp cận khác nhau và biến null vào chai lọ thủy tinh:

bool didSomething = false; 
foreach(var element in someEnumeration ?? Enumerable.Empty<MyType>()) 
{ 
    //some sensible thing to do on element... 
    didSomething = true; 
} 
if(!didSomething) 
{ 
    //handle the fact that it was null or empty (without caring which). 
} 

Tương tự như vậy (someEnumeration ?? Enumerable.Empty<MyType>()).ToList() vv có thể được sử dụng.

+0

Bạn có thể cho tôi ví dụ về bộ sưu tập không thể tua lại trong .NET không? Tôi có nghĩa là chỉ cần tên của một lớp học hiện có trong khuôn khổ, không yêu cầu bạn để cho tôi một ví dụ thực hiện một. – AaronLS

+0

@AaronLS kết quả của hầu hết các truy vấn LINQ. –

+0

Loại bê tông trong trường hợp đó là gì? Tôi biết về IQueryable mà không thực sự là một danh sách cho đến khi bạn cố gắng ToList/foreach tại thời điểm nó được vật chất hóa. Tôi tưởng tượng có một số loại bê tông trung gian cho IQueryable là một trình đọc dữ liệu phía trước chỉ dưới mui xe, vì vậy những gì bạn nói có ý nghĩa, tôi chỉ không thể tưởng tượng nơi bạn thực sự gặp vấn đề này. Nếu bạn 'foreach (var item trong someQueryable)' sẽ tạo ra eneumerator của riêng nó, và sau đó đã làm 'someQueryable.Any()' sẽ là một truy vấn riêng biệt và sẽ không ảnh hưởng đến điều tra viên hiện tại AFAIK. – AaronLS

1

Như mọi người khác đã nói, không có gì được xây dựng trong khuôn khổ, nhưng nếu bạn đang sử dụng Lâu đài thì Castle.Core.Internal có nó.

using Castle.Core.Internal; 

namespace PhoneNumbers 
{ 
    public class PhoneNumberService : IPhoneNumberService 
    { 
     public void ConsolidateNumbers(Account accountRequest) 
     { 
      if (accountRequest.Addresses.IsNullOrEmpty()) // Addresses is List<T> 
      { 
       return; 
      } 
      ... 
0

Tôi đã sửa đổi đề xuất từ ​​Matthew Vines để tránh sự cố "Có thể liệt kê nhiều IEnumerable". (xem thêm các bình luận từ Jon Hanna)

public static bool IsNullOrEmpty(this IEnumerable items) 
    => items == null 
    || (items as ICollection)?.Count == 0 
    || !items.GetEnumerator().MoveNext(); 

... và các đơn vị kiểm tra:

[Test] 
public void TestEnumerableEx() 
{ 
    List<int> list = null; 
    Assert.IsTrue(list.IsNullOrEmpty()); 

    list = new List<int>(); 
    Assert.IsTrue(list.IsNullOrEmpty()); 

    list.AddRange(new []{1, 2, 3}); 
    Assert.IsFalse(list.IsNullOrEmpty()); 

    var enumerator = list.GetEnumerator(); 
    for(var i = 1; i <= list.Count; i++) 
    { 
     Assert.IsFalse(list.IsNullOrEmpty()); 
     Assert.IsTrue(enumerator.MoveNext()); 
     Assert.AreEqual(i, enumerator.Current); 
    } 

    Assert.IsFalse(list.IsNullOrEmpty()); 
    Assert.IsFalse(enumerator.MoveNext()); 
} 
0
var nullOrEmpty = !(list?.Count > 0); 
+0

Chỉ có câu trả lời cho mã không phải là câu trả lời hay, hãy thử thêm một vài dòng giải thích vấn đề là gì và cách sửa mã của bạn – MikeT

+0

Điều này sẽ không biên dịch nếu danh sách là IEnumerable. –

16

Cuối cập nhật: từ C# 6.0, các nhà điều hành null-tuyên truyền có thể được sử dụng để diễn tả ngắn gọn như thế này:

if (enumerable?.Any() ?? false) 

Lưu ý 1:?? false là cần thiết, vì các lý do sau (tóm tắt/quote từ this post):

?. điều hành sẽ trở lại null nếu một thành viên trẻ là null. Nhưng [...] nếu chúng tôi cố gắng để có được một phi Nullable thành viên, giống như Any() phương pháp, mà trả bool [...] trình biên dịch sẽ "quấn" một giá trị trả về trong Nullable<>. Ví dụ: Object?.Any() sẽ cho chúng tôi bool? (là Nullable<bool>), không phải bool. [...] Kể từ khi nó không thể được ngầm Casted đến bool biểu hiện này có thể không được sử dụng trong if

Note 2: như một phần thưởng, báo cáo kết quả cũng là "thread-safe" (trích dẫn từ câu trả lời của this question):

trong một bối cảnh đa luồng, nếu [đếm] có thể truy cập từ một ren (hoặc vì đó là một lĩnh vực mà có thể truy cập hoặc vì nó đóng cửa hơn trong một lambda đó là e xposed để thread khác) thì giá trị có thể là khác nhau mỗi lần nó tính [ieprior null-kiểm tra]

+0

@ GrimR3 Vâng, bạn nói đúng: đó là eo biển hơn với câu hỏi. Tôi đã viết nó như thế để được nội tuyến với các trích dẫn/referece. –

1

Đưa hợp các câu trả lời trước vào một phương pháp mở rộng đơn giản cho C# 6.0+:

public static bool IsNullOrEmpty<T>(this IEnumerable<T> me) => !me?.Any() ?? true; 
Các vấn đề liên quan