0

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
}
adam0101
  • 29,096
  • 21
  • 96
  • 174
  • What would the purpose of this be? – FreeAsInBeer Mar 31 '11 at 04:03
  • 1
    I'm not aware of anything built into the framework, and your implementation seems to do what you want. The only thing I would mention is that your code could easily run into problems if multiple threads called GetEnumerator() concurrently. – dlev Mar 31 '11 at 04:06
  • 3
    Why do you want to loop through and perform your action on all of them before returning any? You could more easily perform the action and `yield return` each item as you iterate thus requiring only one iteration and further defering execution of the action. – Samuel Neff Mar 31 '11 at 04:21

2 Answers2

2

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
}  
Alan
  • 1,301
  • 9
  • 12
2

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)

Euphoric
  • 12,645
  • 1
  • 30
  • 44