2010-07-06 8 views

Antwort

25

Single und SingleOrDefault sind entworfen, um zu werfen, wenn mehr als eine Übereinstimmung in der Sequenz vorhanden ist. Eine Konsequenz daraus ist, dass die gesamte Sequenz vor dem Abschluss iteriert werden muss. Es klingt nicht so, als ob Sie das wollen. Versuchen Sie FirstOrDefault statt:

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

Dies wird (in der Regel) eine bessere Leistung, da es, sobald eine Übereinstimmung gefunden wird vervollständigt.

Natürlich, wenn Sie tatsächlich mehr als ein Element beibehalten möchten, eine Where-Klausel wäre besser geeignet:

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

Wenn Sie nur das erste Element möchten, FirstOrDefault stattdessen verwenden.

Grundsätzlich sind hier die Möglichkeiten in Bezug auf gültige Ergebnisse (dh, wenn Sie nicht wollen, werfen) und was zu verwenden:

  • Genau ein: Single
  • Eins oder Null: SingleOrDefault
  • Ein oder mehr: First
  • Null oder mehr: FirstOrDefault

(ElementAt und ElementAtOrDefault, Last und LastOrDefault sind ebenfalls erhältlich.)

2

Single bedeutet, dass Sie ein Element in der Sequenz sein erwarten. SingleOrDefault bedeutet, dass Sie erwarten, dass in der Sequenz ein oder null Elemente vorhanden sind. Dies sollte verwendet werden, wenn Sie wissen wollen, dass es eine (oder Null) gibt und Sie möchten, dass sie abstürzt, wenn mehr als eine zurückgegeben wird.

Wenn Sie nach nur einem suchen, verwenden Sie First (oder) wie oben vorgeschlagen, aber stellen Sie sicher, dass Sie die Daten richtig bestellen.

3

SingleOrDefault schlägt vor, dass Sie 0 oder 1 Ergebnisse von Ihrer Abfrage erwarten. Wenn Sie mehr als 1 haben, stimmt etwas nicht mit Ihren Daten oder Ihrer Anfrage.

Wenn Sie mehr als 1 Ergebnis erwarten und nur das erste wollen, dann sollte FirstOrDefault verwendet werden.

14

Alternativ verwenden, wenn Sie das Einzelteil wünschen, wenn es genau ein Spiel ist und nicht will, werfen, wenn es mehr als eine gibt, dies leicht erreicht werden kann.Ich habe eine Erweiterungsmethode für den in meinem Projekt erstellt:

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

Danke dafür, ich benutze dies derzeit. Ich habe es in 'ExclusiveOrDefault' umbenannt und außerdem eine Extension-Methode' Exclusive' erstellt, die einen Fehler auslöst, wenn es * zero * -Elemente gibt, aber null gibt, wenn * 2 oder mehr * Elemente vorhanden sind. –

3

ich gefunden habe, ich brauche das Verhalten einen Standardwert zurückkehrt, wenn es nicht genau ein Element (dh null, zwei oder mehr) mehr oft als ich das normale SingleOrDefault Verhalten benötigen, ist hier so meine angepasste Version von 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(); 
    } 
} 

ich die null-Argument Kontrollen verzichtet habe, weil ich mit Berufung auf die Take und Where Anrufe OK bin Ausnahmen zu werfen, wenn die Argumente sind null, aber Sie könnten sich anders fühlen.

+0

Schön. Ich habe das longitudinale SingleOrDefaultIfMultiple() jedoch in OnlyOrDefault() umbenannt. Deine Kommentare deuten sogar so an ... – Marcel

+0

Oder was ist mit "TheOneOrDefault" (Ich habe kürzlich die "Matrix" -Trilogie rewatched) hehe .... – Marcel

+1

@Marcel Ich mag 'OnlyOrDefault()', aber Teil meines Grundes für den längeren Namen ist es also eine IntelliSense-Option, wenn ich (oder andere Teammitglieder) mit der Eingabe von '.SingleOrDefault' beginnen und hoffentlich am Ende den für die Situation passenden auswählen. –

Verwandte Themen