2010-07-06 24 views

Trả lời

25

Single and SingleOrDefault được thiết kế để ném nếu có nhiều hơn một kết quả phù hợp tồn tại trong chuỗi. Hậu quả của việc này là toàn bộ chuỗi phải được lặp lại trước khi hoàn thành. Có vẻ như đây không phải là điều bạn muốn. Hãy thử FirstOrDefault thay thế:

Feature f = o.Features 
    .FirstOrDefault(e => e.vcr_LinkName == PageLink && e.bit_Activate == true); 

Điều này sẽ (thường) hoạt động tốt hơn vì hoàn thành ngay khi tìm thấy kết quả phù hợp.

Tất nhiên, nếu bạn thực sự muốn giữ lại nhiều hơn một phần tử, một mệnh đề WHERE sẽ thích hợp hơn:

IEnumerable<Feature> fs = o.Features 
    .Where(e => e.vcr_LinkName == PageLink && e.bit_Activate == true); 
11

Nếu bạn chỉ muốn các yếu tố đầu tiên, sử dụng FirstOrDefault để thay thế.

Về cơ bản, đây là những tùy chọn về kết quả hợp lệ (tức là nơi mà bạn không muốn ném) và những gì để sử dụng:

  • Đúng một: Single
  • Một hoặc zero: SingleOrDefault
  • Một hoặc nhiều: First
  • Zero hoặc hơn: FirstOrDefault

(ElementAtElementAtOrDefault, LastLastOrDefault cũng có sẵn.)

2

Single có nghĩa là bạn mong đợi là một phần tử trong dãy. SingleOrDefault có nghĩa là bạn mong đợi có một hoặc 0 phần tử trong chuỗi. Điều này nên được sử dụng khi bạn muốn biết có một (hoặc không) và bạn muốn nó sụp đổ khi nhiều hơn một nó trở lại.

Nếu bạn chỉ sau một, hãy sử dụng First (hoặc FirstOrDefault) như được đề xuất ở trên, nhưng đảm bảo bạn đặt hàng dữ liệu chính xác.

3

SingleOrDefault cho thấy bạn đang mong đợi 0 hoặc 1 kết quả từ truy vấn của mình. Nếu bạn có nhiều hơn 1 thì có điều gì đó sai với dữ liệu hoặc truy vấn của bạn.

Nếu bạn mong đợi nhiều hơn 1 kết quả và chỉ muốn kết quả đầu tiên, thì FirstOrDefault nên được sử dụng.

1

Nếu bạn đang sử dụng SingleOrDefault nếu điều kiện thỏa mãn nhiều hơn kết quả, nó sẽ phát sinh lỗi.

bạn có thể đạt được kết quả của bạn bằng cách sử dụng FirstOrDefault

14

Ngoài ra, nếu bạn chỉ muốn mục khi có chính xác là một trong những trận đấu và không muốn để ném khi có nhiều hơn một, điều này có thể dễ dàng thực hiện.Tôi đã tạo ra một phương pháp khuyến nông cho điều này trong dự án của tôi:

public static class QueryableExtensions 
{ 
    public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 

     var results = source.Take(2).ToArray(); 

     return results.Length == 1 ? results[0] : default(TSource); 
    } 

    public static TSource SingleWhenOnly<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) 
    { 
     if (source == null) 
      throw new ArgumentNullException("source"); 
     if (predicate == null) 
      throw new ArgumentNullException("predicate"); 

     var results = source.Where(predicate).Take(2).ToArray(); 

     return results.Length == 1 ? results[0] : default(TSource); 
    } 
} 
+1

Cảm ơn vì điều này, tôi hiện đang sử dụng tính năng này. Tôi đổi tên nó thành 'ExclusiveOrDefault' và cũng đã thực hiện một phương thức mở rộng' Exclusive' để ném lỗi khi có * zero * elements, nhưng trả về null khi có * 2 hoặc nhiều hơn * elements. –

3

tôi đã tìm thấy tôi cần những hành vi trả lại một giá trị mặc định nếu không có đúng một phần tử (tức là không, hai, hoặc nhiều hơn) hơn thường xuyên hơn tôi cần SingleOrDefault hành vi bình thường, vì vậy đây là phiên bản chuyển thể của tôi về Pieter van Ginkel's answer:

public static class LinqExtensions 
{ 
    /// <summary> 
    /// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element. 
    /// </summary> 
    public static TSource SingleOrDefaultIfMultiple<TSource>(this IEnumerable<TSource> source) 
    { 
     var elements = source.Take(2).ToArray(); 

     return (elements.Length == 1) ? elements[0] : default(TSource); 
    } 

    /// <summary> 
    /// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element. 
    /// </summary> 
    public static TSource SingleOrDefaultIfMultiple<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) 
    { 
     return source.Where(predicate).SingleOrDefaultIfMultiple(); 
    } 

    /// <summary> 
    /// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element. 
    /// </summary> 
    public static TSource SingleOrDefaultIfMultiple<TSource>(this IQueryable<TSource> source) 
    { 
     var elements = source.Take(2).ToArray(); 

     return (elements.Length == 1) ? elements[0] : default(TSource); 
    } 

    /// <summary> 
    /// Returns the only element of a sequence, or a default value if the sequence is empty or contains more than one element. 
    /// </summary> 
    public static TSource SingleOrDefaultIfMultiple<TSource>(this IQueryable<TSource> source, Expression<Func<TSource, bool>> predicate) 
    { 
     return source.Where(predicate).SingleOrDefaultIfMultiple(); 
    } 
} 

tôi đã bỏ qua kiểm tra đối số null bởi vì tôi là OK với dựa vào TakeWhere cuộc gọi để ném ngoại lệ khi đối số là null, nhưng bạn có thể cảm thấy khác.

+0

Đẹp. Tôi đã đổi tên thành SingleOrDefaultIfMultiple() thành OnlyOrDefault() dài. Ý kiến ​​của bạn thậm chí còn đề xuất như vậy .... – Marcel

+0

Hoặc, những gì về "TheOneOrDefault" (Gần đây tôi đã rewatched "The Matrix" bộ ba) hehe .... – Marcel

+1

@Marcel Tôi thích 'OnlyOrDefault()', nhưng một phần lý do của tôi cho tên dài hơn vì vậy nó sẽ đi lên như là một tùy chọn intellisense khi tôi (hoặc các thành viên trong nhóm) bắt đầu gõ '.SingleOrDefault' và chúng tôi hy vọng sẽ chọn một trong đó là thích hợp cho tình hình. –

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