Reputation: 9393
Suppose I have something like this:
IEnumerable<T> result = BuildAList<T>()
// lots of LINQ operators
;
But maybe BuildAList
is expensive, and I don't want to call it unless and until someone actually starts iterating over result
. Is there a simple, idiomatic way to do this?
(I can obviously write my own IEnumerable<T>
class, but I'm hoping there's a way to do it with the existing operators etc.)
Upvotes: 1
Views: 439
Reputation: 205749
I'm afraid currently there is no standard method for doing that, so you have to roll your own. It cannot be extension method, so should be regular static method with iterator block (using yield return
) and factory delegate similar to Lazy<T>
which will ensure the desired deferred execution.
Something like this:
public static class Iterators
{
public static IEnumerable<T> Lazy<T>(Func<IEnumerable<T>> factory)
{
foreach (var item in factory())
yield return item;
}
}
And use it as follows:
var result = Iterators.Lazy(() => BuildAList<T>());
// lots of LINQ operators
;
Edit: The downside of the above implementation is that the factory method will be invoked for each execution of the returned enumerable. It can be avoided by combining the implementation with Lazy<T>
class:
public static class Iterators
{
public static IEnumerable<T> Lazy<T>(Func<IEnumerable<T>> factory)
{
return LazyIterator(new Lazy<IEnumerable<T>>(factory));
}
private static IEnumerable<T> LazyIterator<T>(Lazy<IEnumerable<T>> source)
{
foreach (var item in source.Value)
yield return item;
}
}
Upvotes: 4
Reputation: 435
You could make result into a lazy property and have the downstream stuff reference that.
class MyClass<T>
{
IEnumerable<T> result;
IEnumerable<T> Result
{
get { return result ?? (result = BuildAList()); }
}
List<T> BuildAList()
{
//...
}
}
Upvotes: 1
Reputation: 74
use this model generic method:
public virtual IList<T> GetList(Func<T, bool> where,
params Expression<Func<T, object>>[] navigationProperties)
{
List<T> list;
using (var context = new DbEntities())
{
IQueryable<T> dbQuery = context.Set<T>();
//Apply eager loading
foreach (Expression<Func<T, object>> navigationProperty in navigationProperties)
dbQuery = dbQuery.Include<T, object>(navigationProperty);
list = dbQuery
.AsNoTracking()
.Where(where)
.ToList<T>();
}
return list;
}
Upvotes: 1