2010-09-22 13 views
6

miałem następującą instrukcję, która zawsze zwraca NULL:Dlaczego zerowa jest nieprawidłowa projekcja LINQ?

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

Zmieniłem go lekko, a teraz działa dobrze:

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

Moim głównym pytaniem: Dlaczego nie może służyć jako zerowy zwraca typ z operatora trójskładnikowego w tym kontekście LINQ?

Drugie pytanie: czy istnieje bardziej sprytny sposób sformułowania powyższej kwerendy (szczególnie, jeśli eliminuje "nową listę()")?

Odpowiedz

11

Enumerable.SelectMany będzie próbował wyliczyć nad sekwencji zwróconej przez lambda i rzuca NullReferenceException próby wywołania GetEnumerator() na null. Musisz podać rzeczywistą pustą sekwencję. Zamiast utworzyć nową listę, można użyć Enumerable.Empty:

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

Podejrzewam, co rzeczywiście chcesz, to po prostu zadzwonić Gdzie przed SelectMany odfiltrować zestawy nie chcesz:

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

Lub w składni zapytania:

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

Doskonała odpowiedź i spostrzeżenia. Nawiasem mówiąc, obsada "set.addins" nie jest konieczna w innych przykładach, ponieważ operator trójczłonowy nie jest zaangażowany. –

1

Dokonaj że:

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

+0

Próbowałem już tego. Nic nie zmieniło. :( –

Powiązane problemy