内置.Net IEnumerable类,推迟执行?

时间:2011-03-31 04:00:28

标签: c# .net ienumerable deferred-execution delayed-execution

我正要构建我自己的IEnumerable类,它会在第一次迭代它时对所有项执行某些操作然后我开始疑惑,框架是否已经有了我可以使用的东西?

这就是我正在构建的内容,因此您可以了解我正在寻找的内容:

public class DelayedExecutionIEnumerable<T> : IEnumerable<T>
{
    IEnumerable<T> Items;
    Action<T> Action;
    bool ActionPerformed;

    public DelayedExecutionIEnumerable(IEnumerable<T> items, Action<T> action)
    {
        this.Items = items;
        this.Action = action;
    }

    void DoAction()
    {
        if (!ActionPerformed)
        {
            foreach (var i in Items)
            {
                Action(i);
            }
            ActionPerformed = true;
        }
    }

    #region IEnumerable<IEntity> Members

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

    #endregion

    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        DoAction();
        return Items.GetEnumerator();
    }

    #endregion
}

2 个答案:

答案 0 :(得分:2)

我不确定有什么东西能完全符合您的要求,但我建议您使用Lazy&lt; T&gt;为此,它将处理线程安全问题(针对每个单独的项目):

public class DelayedExecutionIEnumerable<T> : IEnumerable<T>
{
    List<Lazy<T>> LazyItems;

    public DelayedExecutionIEnumerable(IEnumerable<T> items, Action<T> action)
    {
        // Wrap items into our List of Lazy items, the action predicate
        // will be executed only once on each item the first time it is iterated.
        this.LazyItems = items.Select(
            item => new Lazy<T>(
                () => 
                    {
                        action(item);
                        return item;
                    }, 
                    true)).ToList(); // isThreadSafe = true 
    }

    #region IEnumerable<IEntity> Members

    public IEnumerator<T> GetEnumerator()
    {
        return this.LazyItems.Select(i => i.Value).GetEnumerator();
    }

    #endregion


    #region IEnumerable Members

    System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
    {
        return this.LazyItems.Select(i => i.Value).GetEnumerator();
    }

    #endregion
}  

答案 1 :(得分:2)

Iteratorsyield可让您轻松创建自己的惰性枚举器序列。

同样在您的情况下,您可能很容易滥用LINQ的Select方法。

items.Select(i=>{DoStuff(i); return i;});

也许把它包起来?

public static IEnumerable<T> DoStuff<T>(this IEnumerable<T> items, Action<T> doStuff)
{
    return items.Select(i=>{doStuff(i); return i;});
}

(手写未经测试的代码,请谨慎使用)