Is there a built-in way to convert IEnumerator to IEnumerable

前端 未结 8 1726
面向向阳花
面向向阳花 2020-12-30 18:55

Is there a built-in way to convert IEnumerator to IEnumerable?

8条回答
  •  隐瞒了意图╮
    2020-12-30 19:15

    This is a variant I have written... The specific is a little different. I wanted to do a MoveNext() on an IEnumerable, check the result, and then roll everything in a new IEnumerator that was "complete" (so that included even the element of the IEnumerable I had already extracted)

    // Simple IEnumerable that "uses" an IEnumerator that has
    // already received a MoveNext(). "eats" the first MoveNext() 
    // received, then continues normally. For shortness, both IEnumerable
    // and IEnumerator are implemented by the same class. Note that if a
    // second call to GetEnumerator() is done, the "real" IEnumerator will
    // be returned, not this proxy implementation.
    public class EnumerableFromStartedEnumerator : IEnumerable, IEnumerator
    {
        public readonly IEnumerator Enumerator;
    
        public readonly IEnumerable Enumerable;
    
        // Received by creator. Return value of MoveNext() done by caller
        protected bool FirstMoveNextSuccessful { get; set; }
    
        // The Enumerator can be "used" only once, then a new enumerator
        // can be requested by Enumerable.GetEnumerator() 
        // (default = false)
        protected bool Used { get; set; }
    
        // The first MoveNext() has been already done (default = false)
        protected bool DoneMoveNext { get; set; }
    
        public EnumerableFromStartedEnumerator(IEnumerator enumerator, bool firstMoveNextSuccessful, IEnumerable enumerable)
        {
            Enumerator = enumerator;
            FirstMoveNextSuccessful = firstMoveNextSuccessful;
            Enumerable = enumerable;
        }
    
        public IEnumerator GetEnumerator()
        {
            if (Used)
            {
                return Enumerable.GetEnumerator();
            }
    
            Used = true;
            return this;
        }
    
        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }
    
        public T Current
        {
            get
            {
                // There are various school of though on what should
                // happens if called before the first MoveNext() or
                // after a MoveNext() returns false. We follow the 
                // "return default(TInner)" school of thought for the
                // before first MoveNext() and the "whatever the 
                // Enumerator wants" for the after a MoveNext() returns
                // false
                if (!DoneMoveNext)
                {
                    return default(T);
                }
    
                return Enumerator.Current;
            }
        }
    
        public void Dispose()
        {
            Enumerator.Dispose();
        }
    
        object IEnumerator.Current
        {
            get
            {
                return Current;
            }
        }
    
        public bool MoveNext()
        {
            if (!DoneMoveNext)
            {
                DoneMoveNext = true;
                return FirstMoveNextSuccessful;
            }
    
            return Enumerator.MoveNext();
        }
    
        public void Reset()
        {
            // This will 99% throw :-) Not our problem.
            Enumerator.Reset();
    
            // So it is improbable we will arrive here
            DoneMoveNext = true;
        }
    }
    

    Use:

    var enumerable = someCollection;
    
    var enumerator = enumerable.GetEnumerator();
    bool res = enumerator.MoveNext();
    // do whatever you want with res/enumerator.Current
    
    var enumerable2 = new EnumerableFromStartedEnumerator(enumerator, res, enumerable);
    

    Now, the first GetEnumerator() that will be requested to enumerable2 will be given through the enumerator enumerator. From the second onward the enumerable.GetEnumerator() will be used.

提交回复
热议问题