csharp 缓存枚举器,确保源枚举器只迭代一次

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了csharp 缓存枚举器,确保源枚举器只迭代一次相关的知识,希望对你有一定的参考价值。

//latest version is here: https://gist.github.com/b1059488d17c52da5a732a100ba6e09f.git
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;

namespace CachingEnumeratorUtils
{
    /// <summary>
    /// Enumerable doing lazy caching of enumerator, to avoid generating items more than one time
    /// </summary>
    /// <typeparam name="T"></typeparam>
    public class CachingEnumerator<T> : IEnumerable<T>, IDisposable
    {
        public CachingEnumerator(IEnumerable<T> source)
        {
            this.sourceEnumerator = source.GetEnumerator();
        }
        public CachingEnumerator(IEnumerator<T> source)
        {
            this.sourceEnumerator = source;
        }

        /// <summary>
        /// Items that were already generated by source enumerator
        /// </summary>
        public IEnumerable<T> CachedItems { get { return cachedItems; } }
        /// <summary>
        /// Amount of items that were cached already
        /// </summary>
        public int CachedItemsCount { get { return cachedItems.Count; } }
        /// <summary>
        /// Indicates if all items cached and source is complete
        /// </summary>
        public bool IsCachedAll { get { return sourceEnumeratorFinished; } }

        //public IEnumerable<T> Source { get; private set; }
        IEnumerator<T> sourceEnumerator;

        LinkedList<T> cachedItems = new LinkedList<T>();
        bool sourceEnumeratorFinished = false;
        bool sourceEnumeratorStarted = false;


        LinkedListNode<T> CacheNext()
        {
            if (sourceEnumeratorFinished) return null;
            sourceEnumeratorStarted = true;
            sourceEnumeratorFinished = !sourceEnumerator.MoveNext();
            if (sourceEnumeratorFinished)
            {
                DisposeSource();
                return null;
            }
            var node = cachedItems.AddLast(sourceEnumerator.Current);
            return node;
        }

        IEnumerable<T> GetItems()
        {
            if (!sourceEnumeratorStarted) CacheNext();

            var current = cachedItems.First;
            while (current != null)
            {
                yield return current.Value;
                current = current.Next ?? CacheNext();
            }
        }

        public IEnumerator<T> GetEnumerator()
        {
            return GetItems().GetEnumerator();
        }

        IEnumerator IEnumerable.GetEnumerator()
        {
            return GetEnumerator();
        }

        bool sourceDisposed = false;
        void DisposeSource()
        {
            if (sourceDisposed) return;
            sourceEnumerator.Dispose();
            sourceDisposed = true;
        }

        public void Dispose()
        {
        }
    }

    /// <summary>
    /// Extensions that help to use CachingEnumerator
    /// </summary>
    public static class CachingEnumeratorExtensions
    {
        /// <summary>
        /// Make sure enumerator will be only iterated once and items generated will be cached
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static CachingEnumerator<T> AsCaching<T>(this IEnumerable<T> source)
        {
            return new CachingEnumerator<T>(source);
        }

        /// <summary>
        /// Make sure enumerator will be only iterated once and items generated will be cached
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="source"></param>
        /// <returns></returns>
        public static CachingEnumerator<T> AsCaching<T>(this IEnumerator<T> source)
        {
            return new CachingEnumerator<T>(source);
        }
    }
}

以上是关于csharp 缓存枚举器,确保源枚举器只迭代一次的主要内容,如果未能解决你的问题,请参考以下文章

C#中的枚举器和迭代器

枚举器和迭代器

csharp 在一个枚举器运行中聚合多个累加器

csharp Xamarinでに选取器枚举をバインド

枚举和迭代器

csharp Python中内置的枚举函数可以把一个列表变成索引 - 元素对,这样就可以在对循环中同时迭代索引和元素本身: