2010-09-22 13 views
6

que tenían la siguiente declaración, que siempre devuelve un valor nulo:¿Por qué Null es una proyección LINQ no válida?

var addins = allocations.SelectMany(
     set => set.locations.Any(q => q.IsMatch(level, count)) 
     ? (List<string>)set.addins : null 
    ); 

he cambiado ligeramente, y ahora funciona bien:

var addins = allocations.SelectMany(
     set => set.locations.Any(q => q.IsMatch(level, count)) 
     ? set.addins : new List<string>() 
    ); 

Mi primera pregunta: ¿Por qué no puede servir como nula Tipo de devolución del operador ternario en este contexto de LINQ?

Una pregunta secundaria: ¿Hay una manera más inteligente de formular la consulta anterior (particularmente si elimina la "nueva Lista()")?

Respuesta

11

Enumerable.SelectMany va a tratar de enumerar sobre la secuencia devuelta por su lambda, y se lanza un NullReferenceException intentando llamar GetEnumerator() en nulo. Debes proporcionar una secuencia vacía real. En lugar de crear una nueva lista, se puede usar Enumerable.Empty:

var addins = allocations.SelectMany(
    set => set.locations.Any(q => q.IsMatch(level, count)) 
    ? (List<string>)set.addins : Enumerable.Empty<string>() 
    ); 

Sospecho que lo que realmente quiere es llamar simplemente Donde antes SelectMany para filtrar los conjuntos que no quiere:

var addins = allocations 
    .Where(set => set.locations.Any(q => q.IsMatch(level, count))) 
    .SelectMany(set => (List<string>)set.addins); 

O, en sintaxis de consulta:

var addins = 
    from set in allocations 
    where set.locations.Any(q => q.IsMatch(level, count)) 
    from addin in (List<string>)set.addins 
    select addin; 
+1

Excelente respuesta e información. Por cierto, el molde en "set.addins" no es necesario en los otros ejemplos, ya que el operador ternario no está involucrado. –

1

Hacer que:

(List<string>)set.addins : (List<string>)null

+0

Ya lo había intentado. No cambió nada. :( –