2011-11-09 27 views
8

Nếu tôi muốn thực hiện các hành động như .Where (...) hoặc .Max (...), tôi cần đảm bảo rằng danh sách không phải là rỗng và có số lớn hơn 0. Bên cạnh việc thực hiện một số việc như sau mỗi lần tôi muốn sử dụng danh sách:Cách tốt hơn để kiểm tra các yếu tố trong danh sách?

if(mylist != null && mylist.Count > 0) 
{...} 

có kỹ thuật nào khác trong nội tuyến hoặc lambda mà tôi có thể sử dụng không? Hoặc một kỹ thuật nén khác?

+5

IMHO, các đối tượng như danh sách không bao giờ nên rỗng. Tôi luôn khởi tạo chúng nếu chúng là một thành viên lớp, và nếu chúng được trả về từ một hàm tạo của riêng tôi, tôi đảm bảo rằng hàm trả về một danh sách rỗng hơn là null. –

+0

Có thể trùng lặp câu trả lời tại: http://stackoverflow.com/questions/41319/checking-if-a-list-is-empty-with-linq – VS1

+0

Bạn luôn có thể viết các phương pháp mở rộng của riêng mình để sử dụng các hành động như Trong đó() hoặc Max() sẽ bao gồm phép thử null và Count của bạn trước khi sử dụng phương thức mở rộng thực tế. – Paul

Trả lời

3

sở thích chung của tôi là phải có trường hợp danh sách trống, thay vì biến danh sách null. Tuy nhiên, không phải ai cũng có thể cajole đồng nghiệp của họ vào sự sắp xếp này. Bạn có thể tự bảo vệ mình khỏi các biến danh sách rỗng bằng cách sử dụng phương thức mở rộng này.

public static IEnumerable<T> EmptyIfNull<T>(this IEnumerable<T> source) 
{ 
    return source ?? Enumerable.Empty<T>(); 
} 

gọi theo:

Customers result = myList.EmptyIfNull().Where(c => c.Name == "Bob"); 

Hầu hết các phương pháp LINQ làm việc trên các bộ sưu tập trống. Hai phương thức không phải là Min và Max. Nói chung, tôi gọi những phương pháp này chống lại một IGrouping. Hầu hết các triển khai IGrouping có ít nhất một phần tử (ví dụ: IGroupings được tạo bởi GroupBy hoặc ToLookup). Đối với các trường hợp khác, bạn có thể sử dụng Enumerable.DefaultIfEmpty.

int result = myList.EmptyIfNull().Select(c => c.FavoriteNumber).DefaultIfEmpty().Max(); 
1

Bạn có thể thử myList.Any() thay vì .Count, nhưng bạn vẫn cần phải kiểm tra null.

+0

Phải, vì vậy bạn vẫn cần kiểm tra giá trị rỗng. – Igor

2

Đừng để danh sách được null

Đảm bảo các đối tượng luôn luôn ở trong trạng thái hợp lệ. Bằng cách đảm bảo danh sách không bao giờ là rỗng, bạn không bao giờ phải kiểm tra xem danh sách có rỗng không.

public class MyClass 
{ 
    private readonly IEnumerable<int> ints; 

    public MyClass(IEnumerable<int> ints) 
    { 
     this.ints = ints; 
    } 

    public IEnumerable<int> IntsGreaterThan5() 
    { 
     return this.ints.Where(x => x > 5); 
    } 
} 

Ngay cả khi danh sách này trống, bạn vẫn nhận được IEnumerable<int> hợp lệ trở lại.

Max và Min quá tải với các loại Nullable

Điều đó vẫn không giải quyết được "Max" và "Min" vấn đề mặc dù. Có quá tải Max và Min có bộ chọn. Những quá tải selector có thể trở lại ints nullable, vì vậy phương pháp tối đa của bạn trở nên này:

this.ints.Max(x => new int?(x)); 

Do đó, bạn chạy Max và kiểm tra xem bạn đã nhận được một giá trị null hay một số nguyên trở lại. thì đấy!

Lựa chọn khác

Phương pháp chỉnh mở rộng

Bạn cũng có thể viết phương pháp khuyến nông của riêng bạn.

public static MinMaxHelper() 
{ 
    public static int? MaxOrDefault(IEnumerable<int> ints) 
    { 
     if(!ints.Any()) 
     { 
      return null; 
     } 

     return ints.Max(); 
    } 

    public static int MaxOrDefault(IEnumerable<int> ints, int defaultValue) 
    { 
     if(!ints.Any()) 
     { 
      return defaultValue; 
     } 

     return ints.Max(); 
    } 
} 

Trọng LINQ Extension Methods

Và cuối cùng, hãy nhớ rằng việc xây dựng trong phương pháp khuyến nông LINQ có thể được overriden với các phương pháp mở rộng của riêng bạn với chữ ký phù hợp. Vì vậy, bạn có thể viết một phương thức mở rộng để thay thế .Where (...) và .Max (...) để trả về null (hoặc một giá trị mặc định) thay vì ném một ArgumentNullException nếu Enumerable là null.

+2

bạn có đang trả lời câu hỏi này không? – Snowbear

+0

Xin lỗi, tôi phải có một ngày tồi tệ. Tôi đã nhìn thấy rất nhiều kiểm tra null và danh sách instantiation bên trong của vòng trong khi và như vậy gần đây, thay vì chỉ instantiating danh sách với lớp. –

1

Nếu có nguy cơ danh sách của bạn bị vô hiệu, bạn sẽ phải kiểm tra trước khi gọi bất kỳ phương pháp nào của nó nhưng bạn có thể sử dụng phương thức Any() thay vì đếm. Điều này sẽ trả về true ngay sau khi nó đếm một mục bất kể nếu có một hoặc nhiều mục trong danh sách. Điều này tiết kiệm iterating trên toàn bộ danh sách đó là những gì Đếm sẽ làm:

if(mylist != null && mylist.Any()) 
{...} 
9
public static class LinqExtensions 
{ 
    public static bool IsNullOrEmpty<T>(this IEnumerable<T> items) 
    { 
      return items == null || !items.Any(); 
    } 
} 

Sau đó bạn có thể làm điều gì đó như

if (!myList.IsNullOrEmpty()) 
.... 
+0

Điều kiện này làm gì '! Items.Any(); '? – sll

+0

@sll, no, Any() sẽ ném một ArgumentNullException nếu nguồn là null. –

+1

nó sẽ không bao giờ thực hiện bởi vì trước khi nó 'items == null' kiểm tra ... – sll

2

Sử dụng empty bộ sưu tập thay vì null bộ sưu tập.Where sẽ hoạt động tốt với bộ sưu tập trống, vì vậy bạn không cần phải đảm bảo rằng Count > 0 trước khi gọi. Bạn cũng có thể gọi số Max trên bộ sưu tập trống nếu trước tiên bạn thực hiện bit of gymnastics.

Đối IEnumerable<T> sử dụng Enumerable.Empty<T>()

Đối T[] sử dụng new T[0]

Đối List<T> sử dụng new List<T>()

1

Bạn có thể sử dụng ?? toán tử chuyển đổi null thành giá trị mà bạn cung cấp ở bên phải:

public ProcessList(IEnumerable<int> ints) 
{ 
    this.ints = ints ?? new List<int>(); 
} 

Bằng cách này: Không có vấn đề gì khi xử lý danh sách trống bằng LINQ.

1

Bạn không cần phải kiểm tra Count để gọi Where. Max cần một danh sách không rỗng với nhiều loại giá trị nhưng có thể được khắc phục với một dàn diễn viên nội tuyến, ví dụ

int? max = new List<int>().Max(i => (int?)i); // max = null 
Các vấn đề liên quan