private async Task PerformDispose(DisposeAsyncDelegate disposeDelegate = null) { var prev = Interlocked.Exchange(ref this._current, null); if (prev != null || disposeDelegate != null) { try { this.IterationEndedEvent?.Invoke(null, new IterationEndedEventArgs()); } catch { // Ignore } if (disposeDelegate == null) { disposeDelegate = prev.Dispose; } if (disposeDelegate != null) { await prev.Dispose(); } } }
public CurrentInfo( T current, MoveNextAsyncDelegate <T> moveNext, DisposeAsyncDelegate disposeDelegate ) { this.MoveNext = moveNext; this.Current = current ?? throw new ArgumentNullException(nameof(current)); this.Dispose = disposeDelegate; }
public async Task <Boolean> MoveNextAsync() { // We can call move next only in initial state, or after we have called it once Boolean retVal = false; var wasNotInitial = Interlocked.CompareExchange(ref this._state, MOVE_NEXT_STARTED, MOVE_NEXT_ENDED) == MOVE_NEXT_ENDED; if (wasNotInitial || Interlocked.CompareExchange(ref this._state, MOVE_NEXT_STARTED, STATE_INITIAL) == STATE_INITIAL) { DisposeAsyncDelegate disposeDelegate = null; try { if (wasNotInitial) { var moveNext = this._current.MoveNext; if (moveNext == null) { retVal = false; } else { T current; (retVal, current) = await moveNext(); if (retVal) { this._current.Current = current; } } } else { // First time calling move next var result = await this._initialMoveNext(); retVal = result.Item1; if (retVal) { Interlocked.Exchange(ref this._current, new CurrentInfo(result.Item2, result.Item3, result.Item4)); } else { disposeDelegate = result.Item4; } } } finally { try { if (!retVal) { await this.PerformDispose(disposeDelegate); } } catch { // Ignore. } if (!retVal) { Interlocked.Exchange(ref this._current, null); } Interlocked.Exchange(ref this._state, retVal ? MOVE_NEXT_ENDED : STATE_ENDED); } } else if (this._state != STATE_ENDED) { // Re-entrancy or concurrent with Reset -> exception throw new InvalidOperationException("Tried to concurrently move to next or reset."); } return(retVal); }