303

So I frequently run into this situation... where Do.Something(...) returns a null collection, like so:

int[] returnArray = Do.Something(...);

Then, I try to use this collection like so:

foreach (int i in returnArray)
{
    // do some more stuff
}

I'm just curious, why can't a foreach loop operate on a null collection? It seems logical to me that 0 iterations would get executed with a null collection... instead it throws a NullReferenceException. Anyone know why this could be?

This is annoying as I'm working with APIs that aren't clear on exactly what they return, so I end up with if (someCollection != null) everywhere.

6
  • 4
    I suppose by the same reasoning it would be well-defined for all statements in C# to become no-ops when given a null value. Are you suggesting this for just foreach loops or other statements as well? Commented Jun 21, 2010 at 20:42
  • 9
    @ Ken... I'm thinking just foreach loops, because to me it seems apparent to the programmer that nothing would happen if the collection is empty or non-existent Commented Jun 21, 2010 at 20:47
  • 1
    Similar to stackoverflow.com/q/6455311/80161 and stackoverflow.com/a/11734449/80161 Commented Oct 9, 2015 at 14:50
  • @Polaris878 since 'null' is the absence of knowledge. Not the knowledge that there's an empty list. Treating 'null' as something it's most definitely is not, is not obvious at all and might hide a sever bug Commented May 3, 2019 at 9:11
  • foreach on null collection is correct to throw the exception. Would you want a method called on a null reference to be a no-op too? Or serialization of a null collection to be equivalent to serialization of empty collection? Null and empty are two different things, and are treated in a consistent way by C# across all scenarios. Commented Nov 8, 2020 at 18:23

12 Answers 12

336

Well, the short answer is "because that's the way the compiler designers designed it." Realistically, though, your collection object is null, so there's no way for the compiler to get the enumerator to loop through the collection.

If you really need to do something like this, try the null coalescing operator:

int[] array = null;

foreach (int i in array ?? Enumerable.Empty<int>())
{
   System.Console.WriteLine(string.Format("{0}", i));
}
Sign up to request clarification or add additional context in comments.

14 Comments

Please excuse my ignorance, but is this efficient? Does it not result in a comparison on each iteration?
I don't believe so. Looking at the generated IL, the loop is after the is null comparison.
Holy necro... Sometimes you have to look at the IL to see what the compiler is doing to figure out if there are any efficiency hits. User919426 had asked whether it did the check for each iteration. Though the answer might be obvious to some people, it is not obvious to everyone, and providing the hint that looking at the IL will tell you what the compiler is doing, helps people fish for themselves in the future.
@Robaticus (even why later) the IL looks that why because the specification says so. The expansion of the syntactic sugar (aka foreach) is to evaluate the expression on the right side of "in" and call GetEnumerator on the result
@RuneFS - exactly. Understanding the specification or looking at the IL is a way to figure out the "why." Or to evaluate whether two different C# approaches boil down to the same IL. That was, essentially, my point to Shimmy above.
|
165

A foreach loop calls the GetEnumerator method.
If the collection is null, this method call results in a NullReferenceException.

It is bad practice to return a null collection; your methods should return an empty collection instead.

6 Comments

I agree, empty collections should always be returned... however i didn't write these methods :)
@Polaris, null coalescing operator to the rescue! int[] returnArray = Do.Something() ?? new int[] {};
I disagree about a bad practice: see ⇒ if a function failed it could either return an empty collection — it is a call to constructor, memory allocation, and perhaps a bunch of a code to be executed. Either you could just return «null» → obviously there's only a code to return and a very short code to check is the argument is «null». It's just a performance.
I'd also add: ofc the coalescing operator creates an empty list either way. But that's already decision of a user: if one calls a function somewhere e.g. inside of a GUI, where a performance isn't significant, they may decide to do so. But if they're doing something that requires a performance, they just insert a check «if a result isn't null, do foreach». Though for high performance usually used C++ :Ь
@Hi-Angel how often are you likely to have a method failling (and thus constructing an object/empty collection) vs. how often would you have to do a null check (last one of course being always if you return null). You're suggestion would thus have a performance issue if the general scenario is that the method doesn't fail
|
65

There is a big difference between an empty collection and a null reference to a collection.

When you use foreach, internally, this is calling the IEnumerable's GetEnumerator() method. When the reference is null, this will raise this exception.

However, it is perfectly valid to have an empty IEnumerable or IEnumerable<T>. In this case, foreach will not "iterate" over anything (since the collection is empty), but it will also not throw, since this is a perfectly valid scenario.


Edit:

Personally, if you need to work around this, I'd recommend an extension method:

public static IEnumerable<T> AsNotNull<T>(this IEnumerable<T> original)
{
     return original ?? Enumerable.Empty<T>();
}

You can then just call:

foreach (int i in returnArray.AsNotNull())
{
    // do some more stuff
}

9 Comments

Yes, but WHY doesn't foreach do a null check before getting the enumerator?
@Polaris878: Because it was never intended to be used with a null collection. This is, IMO, a good thing - since a null reference and an empty collection should be treated separately. If you want to work around this, there are ways.. .I'll edit to show one other option...
@Polaris878: I would suggest rewording your question: "Why SHOULD the runtime do a null check before getting the enumerator?"
I guess I'm asking "why not?" lol it seems like the behavior would still be well defined
@Polaris878: I guess, the way I think of it, returning null for a collection is an error. The way it is now, the runtime gives you a meaningful exception in this case, but it's easy to work around (ie: above) if you don't like this behavior. If the compiler hid this from you, you'd lose the error checking at runtime, but there'd be no way to "turn it off"...
|
24

It is being answer long back but i have tried to do this in the following way to just avoid null pointer exception and may be useful for someone using C# null check operator ?.

     //fragments is a list which can be null
     fragments?.ForEach((obj) =>
        {
            //do something with obj
        });

1 Comment

@kjbartel beat you to this by over a year (at " stackoverflow.com/a/32134295/401246 "). ;) This is the best solution, because it doesn't: a) involve performance degradation of (even when not null) generalizing the whole loop to the LCD of Enumerable (as using ?? would), b) require adding an Extension Method to every Project, and c) require avoiding null IEnumerables (Pffft! Puh-LEAZE! SMH.) to begin with.
12

Another extension method to work around this:

public static void ForEach<T>(this IEnumerable<T> items, Action<T> action)
{
    if(items == null) return;
    foreach (var item in items) action(item);
}

Consume in several ways:

(1) with a method that accepts T:

returnArray.ForEach(Console.WriteLine);

(2) with an expression:

returnArray.ForEach(i => UpdateStatus(string.Format("{0}% complete", i)));

(3) with a multiline anonymous method

int toCompare = 10;
returnArray.ForEach(i =>
{
    var thisInt = i;
    var next = i++;
    if(next > 10) Console.WriteLine("Match: {0}", i);
});

5 Comments

Just missing a closing parenthesis in the 3rd example. Otherwise, beautiful code that can be extended further in interesting ways (for loops, reversing, leaping, etc). Thanks for sharing.
Thanks for such a wonderful code, But i didn't understand the first methods,why you pass console.writeline as parameter,though its printing the array elements.but didnt understand
@AjaySingh Console.WriteLine is just an example of a method that takes one argument (an Action<T>). The items 1, 2 and 3 are showing examples of passing functions to the .ForEach extension method.
@kjbartel's answer (at " stackoverflow.com/a/32134295/401246 " is the best solution, because it doesn't: a) involve performance degradation of (even when not null) generalizing the whole loop to the LCD of Enumerable (as using ?? would), b) require adding an Extension Method to every Project, or c) require avoiding null IEnumerables (Pffft! Puh-LEAZE! SMH.) to begin with (cuz, null means N/A, whereas empty list means, it's appl. but is currently, well, empty!, i.e. an Empl. could have Commissions that's N/A for non-Sales or empty for Sales).
@Tom - but that answer applies only to List<T>, it's the only collection that has .ForEach<T>(), which is dumb, IMO. So you can't use that answer after string.Split() for example, without another perf trade-off of converting the array of strings returned to a list just to use .ForEach(). All these trade-offs are just dumb, they should fix it, or never return null from built-in methods (I don't think it's viable to always return List<T>.
6

Because a null collection is not the same thing as an empty collection. An empty collection is a collection object with no elements; a null collection is a nonexistent object.

Here's something to try: Declare two collections of any sort. Initialize one normally so that it's empty, and assign the other the value null. Then try adding an object to both collections and see what happens.

Comments

4

Just write an extension method to help you out:

public static class Extensions
{
   public static void ForEachWithNull<T>(this IEnumerable<T> source, Action<T> action)
   {
      if(source == null)
      {
         return;
      }

      foreach(var item in source)
      {
         action(item);
      }
   }
}

Comments

3

Because behind the scenes the foreach acquires an enumerator, equivalent to this:

using (IEnumerator<int> enumerator = returnArray.getEnumerator()) {
    while (enumerator.MoveNext()) {
        int i = enumerator.Current;
        // do some more stuff
    }
}

5 Comments

so? Why can't it simply check if it is null first and skip the loop? AKA, exactly what is shown in the extension methods? The question is, is it better to default to skip the loop if null or to throw an exception? I think it's better to skip! Seems likely that null containers are meant to be skipped rather than looped over since loops are meant to do something IF the container is non-null.
@AbstractDissonance You could argue the same with all null references, e.g. when accessing members. Typically this is an error, and if it isn't then it's simple enough to handle this for instance with the extension method which another user has provided as answer.
I don't think so. The foreach is meant to operate over the collection and is different than referencing a null object directly. While one could argue the same, I bet if you analyzed all the code in the world, you would have most foreach loops have null checks of some kind in front of them only to bypass the loop when the collection is "null"(which is hence treated the same as empty). I don't think anyone considers looping over a null collection as something they want to and would rather simply ignore the loop if the collection is null. Maybe, rather, a foreach?(var x in C) could be used.
The point I'm mainly trying to make is that it creates a bit of litter in the code since one has to check every time for no good reason. The extensions, of course, work but a language feature could be added to avoid these things without much issue. (mainly I think the current method produces hidden bugs since the programmer may forget to put the check and hence an exception... because either he expects the check to occur somewhere else before the loop or is thinking that it was pre-initialized(which it may or may have changed). But in either cause, the behavior would be the same as if empty.
@AbstractDissonance Well, with some proper static analysis you know where you could have nulls and where not. If you get a null where you don't expect one it's better to fail instead of silently ignoring problems IMHO (in the spirit of failing fast). Therefore I feel that this is the correct behavior.
3

It is the fault of Do.Something(). The best practice here would be to return an array of size 0 (that is possible) instead of a null.

Comments

2

I think the explanation of why exception is thrown is very clear with the answers provided here. I just wish to complement with the way I usually work with these collections. Because, some times, I use the collection more then once and have to test if null every time. To avoid that, I do the following:

    var returnArray = DoSomething() ?? Enumerable.Empty<int>();

    foreach (int i in returnArray)
    {
        // do some more stuff
    }

This way we can use the collection as much as we want without fear the exception and we don't polute the code with excessive conditional statements.

Using the null check operator ?. is also a great approach. But, in case of arrays (like the example in the question), it should be transformed into List before:

    int[] returnArray = DoSomething();

    returnArray?.ToList().ForEach((i) =>
    {
        // do some more stuff
    });

2 Comments

Converting to a list just to have access to the ForEach method is one of the things I hate in a codebase.
I agree... I avoid that as much as possible. :(
0

I think it should check for null. Saves code and headache. Here's a simple extension method I made to solve this problem:

    /// <summary>
    /// Loop through nullable list
    /// </summary>
    public static IEnumerable<T> OrEmptyIfNull<T>(this IEnumerable<T> source)
    {
        return source ?? Enumerable.Empty<T>();
    }

Usage:

     @foreach (var e in account.Items.OrEmptyIfNull())
     {
         <tr class="odd:bg-gray-100 cursor-pointer">
      ...

Comments

-4
SPListItem item;
DataRow dr = datatable.NewRow();

dr["ID"] = (!Object.Equals(item["ID"], null)) ? item["ID"].ToString() : string.Empty;

1 Comment

Where is the connection to the question?

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.