2009-05-04 6 views
32

SingleOrDefault renvoie null, mais que se passe-t-il si je veux attribuer des valeurs pour représenter l'objet qui n'a pas été trouvé?SingleOrDefault: Comment changer les valeurs par défaut?

+0

Avez-vous trouvé une réponse? vous ne pouvez pas modifier les valeurs par défaut en tant que promesses par méthode. car SingleOrDefault doit être SingleOrNull mais il peut renvoyer un objet value. qui peut dire return 0 pour int, c'est un nombre par défaut ou supposé? SingleOrDefault peut renvoyer 0 mais il ne doit pas être par défaut. renvoie null ou non. c'est un mauvais paradigme pour la POO. –

Répondre

5

Vous pouvez rouler le vôtre.

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

Cela peut être un peu cher mais parce que Count() vous oblige à traiter toute la collection et peut être assez coûteux. Il serait préférable soit appeler unique, attraper le InvalidOperationException ou rouler une méthode 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

Cela renverrait la valeur par défaut si l'énumérable contenait plusieurs objets. Ne devrait-il pas lancer une exception comme le fait l'implémentation standard? – tvanfosson

+0

@tvanfosson ouais il devrait. J'avais l'impression que SingleOrDefault retournerait la valeur par défaut s'il y avait autre chose qu'un élément. Mais apparemment, cela ne le fera que pour aucun élément. Bizarre, je vais mettre à jour. – JaredPar

52

vous pouvez faire quelque chose comme

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

départ here

+0

Approche différente +1 – ichiban

+3

+1 pour m'apprendre une nouvelle méthode – ajbeaven

0

Vous pouvez créer vos propres méthodes d'extension - 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

Le problème avec cette approche est que vous allez retourner le paramètre newValue pour une collection qui contient un seul élément avec la valeur null. Considérez cette expression (nouvelle chaîne [] {null}). SingleOrNew ("foo") ;. Cela retournerait incorrectement "foo" – JaredPar

+0

@JaredPar - Je suis prêt à vivre avec ça. Généralement, je ne mets pas de null dans mes collections et si je devais en trouver une en utilisant une méthode comme celle-ci, je voudrais probablement la remplacer par ma valeur par défaut de toute façon. – tvanfosson

+1

@tvanfosson, c'est un changement de rupture assez substantiel par rapport à l'algorithme d'origine qui fait une lourde supposition sur la façon dont les gens utilisent null. – JaredPar

24

?? operator. Si l'argument left est null, évaluez et renvoyez le second argument.

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

Cela ne fonctionne qu'avec les types de référence (ou nullables), mais ce serait faire ce que vous cherchez tout simplement.

+3

Une petite salve d'applaudissements se passe dans ma tête quand j'utilise une coalescence nulle. +1 – Stimul8d

+0

@Joe Je pense que l'OP veut réellement changer la valeur par défaut qui est directement retournée par SingleOrDefault(), par exemple. Si vous recherchez un objet Personne et qu'aucun n'existe, il peut vouloir que SingleOrDefault() renvoie un objet NullPerson. Ma compréhension est qu'il n'est pas possible de changer le type de retour et le problème doit être résolu comme vous l'avez fait, mais encore une fois je pense qu'il est important de clarifier pour l'OP que la valeur de retour par défaut de SingleOrDefault() ne peut pas être modifié. – Matt

Questions connexes