Question

I was about to build my own IEnumerable class that performs some action on all items the first time something iterates over it then I started wondering, does the framework already have something that I could use?

Here's what I was building so you have an idea what I'm looking for:

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
}
Was it helpful?

Solution

Iterators and yield allows you to easily create your own lazy enumerator sequence.

Also in your case, you could easily abuse Select method of LINQ.

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

Maybe wrapping it up?

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

(hand-written not tested code, use with caution)

OTHER TIPS

I'm not sure there is something that does exactly what you are trying to do, but I would recommend you to use Lazy<T> for this, it will take care of Thread safety issues (for each individual item):

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
}  
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top