title: .NET Implement IEnumerator with nullable reference types
body: <p>Since the <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8" rel="noreferrer">release of C# 8.0</a>, I've really been enjoying the 'void safety' with <a href="https://docs.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-8#nullable-reference-types" rel="noreferrer">nullable reference types</a>. However, while tweaking a library of mine to support the new feature, I stumbled upon a 'problem' to which I really couldn't find an answer anywhere. I've looked at Microsoft's release notes and the .NET source code but no luck.</p>
  
  <p>TL;DR: the question is essentially whether or not an <code>IEnumerator&lt;T&gt;</code>'s <code>Current</code> property should be declared as a nullable reference type.</p>
  
  <p>Suppose the following implementation of <code>IEnumerator&lt;T&gt;</code>:</p>
  
  <pre><code>public class WebSocketClientEnumerator&lt;TWebSocketClient&gt; : IEnumerator&lt;TWebSocketClient&gt; where TWebSocketClient : WebSocketClient
  {
      private WebSocketRoom&lt;TWebSocketClient&gt; room;
      private int curIndex;
      private TWebSocketClient? curCli;
  
      public WebSocketClientEnumerator(WebSocketRoom&lt;TWebSocketClient&gt; room)
      {
          this.room = room;
          curIndex = -1;
          curCli = default(TWebSocketClient);
      }
  
      public bool MoveNext()
      {
          if (++curIndex &gt;= room.Count)
          {
              return false;
          }
          else
          {
              curCli = room[curIndex];
          }
  
          return true;
      }
  
      public void Reset() { curIndex = -1; }
  
      void IDisposable.Dispose() { }
  
      public TWebSocketClient? Current
      {
          get { return curCli; }
      }
  
      object IEnumerator.Current
      {
          get { return Current; }
      }
  }
  </code></pre>
  
  <p>And suppose the following code to consume the enumerator:</p>
  
  <pre><code>public class WebSocketRoom&lt;TWebSocketClient&gt; : ICollection&lt;TWebSocketClient&gt; where TWebSocketClient : WebSocketClient
  {
      // ...
  
      public void UseEnumerator()
      {
          var e = new WebSocketClientEnumerator&lt;TWebSocketClient&gt;(this);
          bool hasNext = e.MoveNext();
          if (hasNext)
          {
              WebSocketClient c = e.Current; // &lt;= Warning on this line
          }
      }
  
      // ...
  }
  </code></pre>
  
  <p>The code, as it is, will generate a warning because, obviously, the return type of <code>WebSocketClientEnumerator&lt;TWebSocketClient&gt;.Current</code> is a nullable reference type.</p>
  
  <p>The <code>IEnumerator</code> interface is designed in such a way that one 'should' call the <code>IEnumerator&lt;T&gt;.MoveNext()</code> method to know beforehand if the enumerator has a next value, thereby accomplishing some kind of void safety but obviously, to the eyes of the compiler this means nothing, calling the <code>MoveNext()</code> method doesn't intrinsically guarantee that the enumerator's <code>Current</code> property is not null.</p>
  
  <p>I would like my library to compile without warnings though and the compiler won't let me leave <code>this.curCli</code> with a <code>null</code> value in the constructor if it is not declared as a nullable reference type and if it is declared nullable then the 'burden' of checking for a null reference is transferred to the client of the library. Granted, enumerators are generally consumed trough <code>foreach</code> statements hence it's mostly handeled by the runtime and it's probably not that big of a deal. It is true that semantically speaking, it makes sense for an enumerator's <code>Current</code> property to be <code>null</code> because there might be no data to enumerate, but I really do see a conflict between the <code>IEnumerator&lt;T&gt;</code> interface and the nullable reference type feature. I'm really wondering if there's a way to make the compiler happy while still maintaining the functionality. And also, what are the conventions in some other languages featuring some void safety mechanisms?</p>
  
  <p>I realize this is kind of an open-ended question but I still think it's appropriate for SO. Thanks in advance!</p>