Search code examples
c#ienumerableienumerator

Why is IEnumerator.Current not nullable?


The return type of IEnumerator.Current is object, not object?. In my opinion, because the non-generic IEnumerable can contain any type of object, including null, IEnumerator.Current should return object? so that the programmer doesn't forget to check for it.

Is there a reason why the return type wasn't changed to object? when nullable reference types were introduced?


Solution

  • It was decided against to avoid "spurious warnings" in foreach loops that are hard to work around to such as this github issue example:

    using System.Windows.Forms;
    
    #nullable enable
    
    void M(Control control) 
    {
        // CS8606: Possible null reference assignment to iteration variable
        //               ↓↓↓↓↓↓↓↓↓↓↓↓
        foreach (Control childControl in control.Controls) // ControlCollection is non-generic
        {
            // Use `childControl`
        }
    }
    

    and it wasn't possible to suppress the warnings:

    foreach (Control childControl! in control.Controls) 
    

    If you want to dig in a bit more:

    "For the non-generic IEnumerator, we don't have any idea whether the type contains nulls or not. If we're forced to annotate it, ? is correct, because it says "it's possible this is null" and we can't prove it's not. But that ends up leading to lots of spurious warnings, in particular when enumerating over supplied collections that won't ever contain null, e.g. enumerating a CookieCollection. Since the non-generic IEnumerator is effectively legacy, our best path forward while maintaining correctness and avoiding causing unnecessary warnings is to simply not annotate IEnumerator.Current at all, leaving it "oblivious"; in that way, we don't make any claims about its state, and leave it up to tooling how to best convey that."