【问题标题】:Built in .Net IEnumerable class that defers execution?内置延迟执行的.Net IEnumerable 类?
【发布时间】:2011-03-31 04:00:28
【问题描述】:

我正要构建自己的 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
}

【问题讨论】:

  • 这样做的目的是什么?
  • 我不知道框架中内置了任何内容,您的实现似乎可以满足您的需求。我唯一要提到的是,如果多个线程同时调用 GetEnumerator(),您的代码很容易遇到问题。
  • 为什么要在返回之前循环遍历并执行所有操作?您可以在迭代时更轻松地执行操作和yield return 每个项目,因此只需要一次迭代并进一步推迟操作的执行。

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


【解决方案1】:

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;});
}

(手写未测试代码,慎用)

【讨论】:

    【解决方案2】:

    我不确定是否有某些东西可以完全满足您的要求,但我建议您为此使用 Lazy,它会解决线程安全问题(针对每个单独的项目):

    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
    }  
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-03-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-17
      相关资源
      最近更新 更多