tags:

views:

61

answers:

3

I had the following statement, which always returns null:

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

I changed it slightly, and now it works fine:

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

My primary question: Why can't null serve as a return type from the ternary operator in this context of LINQ?

A secondary question: Is there a more clever way to formulate the above query (particularly if it eliminates the "new List()")?

A: 

Case null to List<string> as well.

Marcelo Cantos
+1  A: 

Make that:

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

KristoferA - Huagati.com
I had already attempted that. It didn't change anything. :(
Brent Arias
+4  A: 

Enumerable.SelectMany will try to enumerate over the sequence returned by your lambda, and it throws a NullReferenceException trying to call GetEnumerator() on null. You need to supply an actual empty sequence. Rather than create a new list, you could use Enumerable.Empty:

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

I suspect what you actually want is to just call Where before SelectMany to filter out the sets you don't want:

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

Or, in query syntax:

var addins =
    from set in allocations
    where set.locations.Any(q => q.IsMatch(level, count))
    from addin in (List<string>)set.addins
    select addin;
Quartermeister
Excellent answer and insights. Incidentally, the cast on "set.addins" is not necessary in your other examples, since the ternary operator is not involved.
Brent Arias