Why does .NET foreach loop throw NullRefException when collection is null?

前端 未结 11 1864
长发绾君心
长发绾君心 2020-11-28 20:34

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

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


        
相关标签:
11条回答
  • 2020-11-28 21:27

    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 theese 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
        });
    
    0 讨论(0)
  • 2020-11-28 21:29

    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.

    0 讨论(0)
  • 2020-11-28 21:30

    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
    }
    
    0 讨论(0)
  • 2020-11-28 21:34

    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));
    }
    
    0 讨论(0)
  • 2020-11-28 21:36

    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
            });
    
    0 讨论(0)
提交回复
热议问题