9

Below is some linqpad test code. When this runs it errors because the second instance of "item" has a null list of subitems as opposed to an empty list.

I want to treat both situations (null or empty list) in exactly the same way but I wondered if there was a cleaner way than just putting a null check on the list and initialising an empty list when there's a null.

in other words, I could do this:

from si in (i.subitems == null ? new List<item>() : i.subitems)

but that's a little ugly and I wondered how I could improve on that?

public class item
{
    public string itemname { get; set; }
    public List<item> subitems { get; set; }
}

void Main()
{
    List<item> myItemList = new List<item>() 
    {
        new item 
        {
            itemname = "item1",
            subitems = new List<item>()
            {
                new item { itemname = "subitem1" },
                new item { itemname = "subitem2" }
            }
        },
        new item 
        {
            itemname = "item2"
        }
    };

    myItemList.Dump();

    var res = (from i in myItemList
            from si in i.subitems
            select new {i.itemname, subitemname = si.itemname}).ToList();

    res.Dump();
}

as a bonus question, can this same linq query be represented as a lambda and treat nulls the same way?

Cheers, Chris

jason
  • 236,483
  • 35
  • 423
  • 525
Chris Simpson
  • 7,821
  • 10
  • 48
  • 68

4 Answers4

15

You could use the null coalescing operator

var res = (from i in myItemList
           from si in i.subitems ?? new List<item>()
           select new { i.itemname, subitemname = si.itemname }).ToList();

But I think you should just filter the empty ones out

var res = (from i in myItemList
           where i.subitems != null
           from si in i.subitems
           select new { i.itemname, subitemname = si.itemname }).ToList();

As for a lambda version you could say

var res = myItemList.Where(x => x.subitems != null)
                    .SelectMany(
                        x => x.subitems.Select(
                            y => new { x.itemname, subitemname = y.itemname }
                        )
                     );

But the query syntax version is way more readble.

jason
  • 236,483
  • 35
  • 423
  • 525
  • actually that second option is very readable and doesn't mean a new list needs to be created only to be ignored. thanks – Chris Simpson Feb 04 '10 at 18:16
  • @Chris Simpson: I added lambda version since you asked for it. The query syntax version is way more readable. – jason Feb 04 '10 at 18:26
  • 1
    I really think the where clause is the cleanest solution here so I'm marking this as the answer. I was just curious about the lambda equivalent but I agree, it's not as readable. Thanks. – Chris Simpson Feb 04 '10 at 18:58
12
from si in (i.subitems ?? new List<item>())

how about that?

hunter
  • 62,308
  • 19
  • 113
  • 113
  • 1
    yeah, that's better than mine (and I'm kicking myself for not doing that in the first place) but it still means creating an object simply to eliminate it which feels bad – Chris Simpson Feb 04 '10 at 17:49
  • @captncraig For other uses of ??, see http://stackoverflow.com/questions/1689530/how-useful-is-cs-operator/1689544#1689544 – Marcel Gosselin Feb 04 '10 at 17:56
10

You could add an (evil) extension method to do the work for you

public static IEnumerable<T> EnsureNotEmpty<T>(this IEnumerable<T> enumerable) {
  if ( enumerable == null ) {
    return Enumerable.Empty<T>();
  } else { 
    return enumerable;
  }
}
JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
  • Is `Enumerable.Repeat(0)` preferable to `Enumerable.Empty()`? – bdukes Feb 04 '10 at 17:49
  • @bdukes, Enumerable.Empty is better as it's more declarative of your intention. For some reason though I keep forgetting it's a part of the framework and do Repeat(0) instead. – JaredPar Feb 04 '10 at 17:52
  • 4
    The method should be called `EnsureNotNull(...)`. Because `EnsureNotEmpty(...)` sounds like it would add a deliberate item. :-> – herzmeister Feb 04 '10 at 17:58
  • 4
    Why do you say this is evil? I quite like this approach. – Darragh Feb 04 '14 at 11:00
0

An additional method would be not to allow subitems to be null. You could make the item constructor so that it defaults subitem to an empty list and then not allow null in the subitem setter.

That of course assumes you have access to modify item.

The null coalescing operator is what you are looking for as pointed out by Hunter Daley

Brandon Bodnar
  • 8,202
  • 2
  • 36
  • 42