2010-09-22 3 views
6

J'ai eu la déclaration suivante, qui renvoie toujours null:Pourquoi Null est-il une projection LINQ non valide?

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

je l'ai changé un peu, et maintenant il fonctionne très bien:

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

Ma première question: Pourquoi ne peut servir comme nulle type de retour de l'opérateur ternaire dans ce contexte de LINQ?

Une question secondaire: Y a-t-il une façon plus intelligente de formuler la requête ci-dessus (en particulier si elle élimine la "nouvelle Liste()")?

Répondre

11

Enumerable.SelectMany va essayer d'énumérer sur la séquence retournée par votre lambda, et il jette un NullReferenceException essayant d'appeler GetEnumerator() sur null. Vous devez fournir une séquence vide réelle. Plutôt que de créer une nouvelle liste, vous pouvez utiliser Enumerable.Empty:

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

Je soupçonne ce que vous voulez vraiment est d'appeler juste avant Où SelectMany pour filtrer les jeux que vous ne voulez pas:

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

Ou, dans la syntaxe de requête:

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

Excellente réponse et insights Incidemment, le cast sur "set.addins" n'est pas nécessaire dans vos autres exemples, puisque l'opérateur ternaire n'est pas impliqué. –

1

font que:

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

+0

J'avais déjà essayé cela. Cela n'a rien changé. :( –