-1

Is there a built-in/standard way of creating a deferred IEnumerable<T>, given a Func<IEnumerable<T>>? My Google skills may be weak...

Suppose I know that some method Foo that returns an IEnumerable<T> executes immediately (and is perhaps long-running). I want to pass it into method Bar that takes in an IEnumerable<T> but I don't want Foo to be execute its long-running process to return items until Bar starts iterating over the items:

IEnumerable<string> Foo()
{
    var items = GetItems(); // long running process
    return items;
}

void Bar(IEnumerable<string> foo)
{
     /* something else long-running, or return immediately if some pre-condition fails and we don't even want to iterate over foo */
    foreach (var item in foo)
    {
        // do something
    }
}   

void Run()
{
    IEnumerable<string> foo = GetFooWrapper(Foo)
    Bar(items);
}

IEnumerable<string> GetFooWrapper(Func<IEnumerable<string>> foo)
{
    // ???
}

What's the best way of implementing GetFooWrapper? My simplest approach was the following, but if there's some "better" way of doing it, I'd like to know about it. Not that it matters, but R# suggests simplifying it to return foo();.

IEnumerable<string> GetFooWrapper(Func<IEnumerable<string>> foo)
{
    foreach (var item in foo())
    {
        yield return item;
    }
}
Andrew
  • 1,494
  • 1
  • 17
  • 27
  • 1
    I guess if you _really_ didn't want to write the wrapper yourself, you could do something like `Bar(new Func>[] { () => Foo(items) }, x => x());`. But what's wrong with the wrapper? Do you have a _specific_ problem you are trying to solve? If you just want someone to look over your code, you should post on codereview.stackexchange.com instead (being sure to comply with their posting requirements/standards, of course). – Peter Duniho Sep 01 '16 at 23:26
  • Do you have a control over re-designing the `GetItems`? If so, I can suggest and alternative solution – Serge Semenov Sep 02 '16 at 00:14

1 Answers1

0

Sounds like you're looking for the Lazy<T> class. It defers the creation of an object until it is first used.

Here's an example that would defer execution of the Foo method until the Value property is accessed for the first time. Once Foo is executed once, it will not be executed again unless a new Lazy<T> is created.

var items = new Lazy<IEnumerable<string>>(Foo);
foreach(var item in items.Value) // delay starts here
{
    // do work
}
Will Ray
  • 10,621
  • 3
  • 46
  • 61