2009-05-04 14 views
32

SingleOrDefault restituisce null, ma cosa succede se voglio assegnare valori per rappresentare l'oggetto che non è stato trovato?SingleOrDefault: come modificare i valori predefiniti?

+0

hai trovato una risposta? non è possibile modificare l'impostazione predefinita come promessa per metodo. perché SingleOrDefault dovrebbe essere SingleOrNull ma può restituire valore oggetto. chi può dire return 0 per int, è il numero predefinito o presunto? SingleOrDefault può restituire 0 ma non deve essere predefinito. restituisce null o no. è un cattivo paradigma per OOP. –

risposta

5

Si potrebbe rotolare il proprio.

public static T SingleOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) { 
    if (1 != enumerable.Count()) { 
    return defaultValue; 
    } 
    return enumerable.Single(); 
} 

questo può essere un po 'costoso, però, perché il conte() richiede di elaborare l'intera collezione e può essere abbastanza costosa da gestire. Sarebbe meglio a uno chiamare singolo, prendere l'InvalidOperationException o rotolare un metodo IsSingle

public static bool IsSingle<T>(this IEnumerable<T> enumerable) { 
    using (var e = enumerable.GetEnumerator()) { 
    return e.MoveNext() && !e.MoveNext(); 
    } 
} 

public static T SingleOrDefault<T>(this IEnumerable<T> enumerable, T defaultValue) { 
    if (!enumerable.IsSingle()) { 
    if(enumerable.IsEmpty()) { 
     return defaultValue; 
    } 
    throw new InvalidOperationException("More than one element"); 
    } 
    return enumerable.Single(); 
} 
+1

Ciò restituirebbe il valore predefinito se l'enumerable contenesse più oggetti. Non dovrebbe gettare un'eccezione come fa l'implementazione standard? – tvanfosson

+0

@tvanfosson si dovrebbe. Avevo l'impressione che SingleOrDefault restituisse il valore predefinito se c'era qualcosa di diverso da un elemento. Ma apparentemente lo farà solo per nessun elemento. Strano, aggiornerò. – JaredPar

52

si può fare qualcosa di simile

myStrings.DefaultIfEmpty("myDefaultString").Single() 

check out here

+0

Approccio diverso +1 – ichiban

+3

+1 per insegnarmi un nuovo metodo – ajbeaven

0

Si potrebbe creare i propri metodi di estensione - SingleOrNew.

public static class IEnumerableExtensions 
{ 
    public static T SingleOrNew<T>(this IEnumerable<T> enumeration, T newValue) 
    { 
     T elem = enumeration.SingleOrDefault(); 
     if (elem == null) 
     { 
      return newValue; 
     } 
     return elem; 
    } 

    public static T SingleOrNew<T>(this IEnumerable<T> enumeration, Func<T,bool> predicate, T newValue) 
    { 
     T elem = enumeration.SingleOrDefault(predicate); 
     if (elem == null) 
     { 
      return newValue; 
     } 
     return elem; 
    } 
} 
+3

Il problema con questo approccio è che si restituirà il parametro newValue per una raccolta che contiene un singolo elemento con il valore null. Considera questa espressione (nuova stringa [] {null}). SingleOrNew ("pippo") ;. Sarebbe erroneamente restituire "foo" – JaredPar

+0

@JaredPar - Sono disposto a conviverci. Generalmente, non inserisco valori nulli nelle mie raccolte e dovessi trovarne uno quando uso un metodo come questo, probabilmente lo sostituirò comunque con il mio valore predefinito. – tvanfosson

+1

@tvanfosson, si tratta di un cambio sostanziale piuttosto sostanziale dall'algoritmo originale che fa una forte ipotesi su come le persone usano null. – JaredPar

24

?? operator. Se l'argomento di sinistra è nullo, valutare e restituire il secondo argomento.

myCollection.SingleOrDefault() ?? new[]{new Item(...)} 

Questo funziona solo con i tipi di riferimento (o nullables), ma sarebbe fare quello che stai cercando in modo molto semplice.

+3

Un piccolo applauso mi viene in mente quando uso la null coalescenza. +1 – Stimul8d

+0

@Joe Penso che l'OP voglia effettivamente cambiare il valore predefinito che viene restituito direttamente da SingleOrDefault(), ad es. se la ricerca di un oggetto Person e nessuno esiste, allora potrebbe desiderare SingleOrDefault() per restituire un oggetto NullPerson. La mia comprensione è che non è possibile cambiare il tipo di ritorno e il problema deve essere risolto nel modo in cui lo hai fatto, ma ancora una volta penso sia importante chiarire per l'OP che il valore di ritorno predefinito di SingleOrDefault() non può essere cambiato. – Matt

Problemi correlati