2009-05-04 15 views
32

SingleOrDefault devuelve nulo, pero ¿qué sucede si deseo asignar valores para representar el objeto que no se encontró?SingleOrDefault: ¿Cómo cambiar los valores predeterminados?

+0

¿Encontró alguna respuesta? no puede cambiar el valor predeterminado como promesas por método. porque SingleOrDefault debe ser SingleOrNull pero puede devolver el objeto de valor. ¿Quién puede decir return 0 for int, es el número predeterminado o supuesto? SingleOrDefault puede devolver 0 pero no debe ser predeterminado. return null o no. es un mal paradigma para OOP. –

Respuesta

5

Puedes enrollar el tuyo.

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

Esto puede ser un poco caro, porque aunque Count() se requiere para procesar toda la colección y puede ser bastante caro de mantener. Sería mejor que sea una sola llamada, coger el InvalidOperationException o rodar un método 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

Esto devolvería el valor predeterminado si el enumerable contiene múltiples objetos. ¿No debería arrojar una excepción como lo hace la implementación estándar? – tvanfosson

+0

@tvanfosson, sí, debería. Tenía la impresión de que SingleOrDefault devolvería el valor predeterminado si había algo más que un elemento. Pero aparentemente solo lo hará sin elementos. Raro, voy a actualizar. – JaredPar

52

se puede hacer algo como

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

la salida here

+0

Método diferente +1 – ichiban

+3

+1 para enseñarme un nuevo método – ajbeaven

0

Se puede crear sus propios métodos de extensión - 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

El problema con este enfoque es que devolverá el parámetro newValue para una colección que contiene un elemento único con el valor nulo. Considere esta expresión (nueva cadena [] {nulo}). SingleOrNew ("foo") ;. Sería incorrecto devolver "foo" – JaredPar

+0

@JaredPar - Estoy dispuesto a vivir con eso. En general, no pongo valores nulos en mis colecciones y si encontrara uno al usar un método como este, probablemente querría reemplazarlo con mi valor predeterminado de todos modos. – tvanfosson

+1

@tvanfosson, ese es un cambio radical bastante sustancial del algoritmo original que hace una suposición fuerte acerca de cómo las personas usan nulo. – JaredPar

24

?? operator. Si el argumento de la izquierda es nulo, evalúe y devuelva el segundo argumento.

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

esto sólo funcionará con los tipos de referencia (o nullables), pero sería hacer lo que está buscando de manera muy sencilla.

+3

Una pequeña ronda de aplausos se dispara en mi cabeza cuando utilizo la coalescencia nula. +1 – Stimul8d

+0

@Joe Creo que el OP realmente quiere cambiar el valor predeterminado que se devuelve directamente de SingleOrDefault(), p. si busca un objeto Persona y no existe ninguno, puede desear que SingleOrDefault() devuelva un objeto NullPerson. Según entiendo, no es posible cambiar el tipo de devolución y el problema debe resolverse de la manera en que lo hizo, pero de nuevo, creo que es importante aclarar para el OP que el valor de retorno predeterminado de SingleOrDefault() no puede ser cambiado – Matt

Cuestiones relacionadas