Встроенный .Net IEnumerable класс, который откладывает выполнение? - PullRequest
0 голосов
/ 31 марта 2011

Я собирался создать свой собственный класс 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 ]

2 голосов
/ 31 марта 2011

Итераторы и yield позволяют легко создавать собственные последовательности ленивых перечислителей.

Также в вашем случае вы можете легко злоупотреблять Select методом LINQ.

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 голосов
/ 31 марта 2011

Я не уверен, что есть что-то, что делает именно то, что вы пытаетесь сделать, но я бы порекомендовал вам использовать Lazy , для этого он позаботится о проблемах безопасности Thread (для каждого отдельного элемента):

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
}  
...