/// <summary>Marks iteration as being completed, whether successfully or otherwise.</summary>
        public void Complete()
        {
            if (m_task is null)
            {
                m_task = Task.s_cachedCompleted;
            }
            else
            {
                AsyncTaskMethodBuilder <VoidTaskResult> .SetExistingTaskResult(m_task, default);

                // Ensure the box's state is cleared so that we don't inadvertently keep things
                // alive, such as any locals referenced by the async enumerator.  For async tasks,
                // this is implicitly handled as part of the box/task's MoveNext, with it invoking
                // the completion logic after invoking the state machine's MoveNext after the last
                // await (or it won't have been necessary because the box was never created in the
                // first place).  But with async iterators, the task represents the entire lifetime
                // of the iterator, across any number of MoveNextAsync/DisposeAsync calls, and the
                // only hook we have to know when the whole thing is completed is this call to Complete
                // as inserted by the compiler in the compiler-generated MoveNext on the state machine.
                // If the last MoveNextAsync/DisposeAsync call to the iterator completes asynchronously,
                // then that same clearing logic will handle the iterator as well, but if the last
                // MoveNextAsync/DisposeAsync completes synchronously, that logic will be skipped, and
                // we'll need to handle it here.  Thus, it's possible we could double clear by always
                // doing it here, and the logic needs to be idempotent.
                if (m_task is IAsyncStateMachineBox box)
                {
                    box.ClearStateUponCompletion();
                }
            }
        }
Ejemplo n.º 2
0
 /// <summary>Marks the task as successfully completed.</summary>
 public void SetResult()
 {
     if (m_task is null)
     {
         m_task = s_syncSuccessSentinel;
     }
     else
     {
         AsyncTaskMethodBuilder <VoidTaskResult> .SetExistingTaskResult(m_task, default);
     }
 }