Search code examples
c#entity-frameworklinqienumerablelazy-evaluation

Force IEnumerable<T> to evaluate without calling .ToArray() or .ToList()


If I query EF using something like this...

IEnumerable<FooBar> fooBars = db.FooBars.Where(o => o.SomeValue == something);

IIRC, This creates a lazy-evaluated, iterable state machine in the background, that does not yet contain any results; rather, it contains an expression of "how" to obtain the results when required.

If I want to force the collection to contain results I have to call .ToArray() or .ToList()

Is there a way to force an IEnumerable<T> collection to contain results without calling .ToArray() or .ToList(); ?

Rationale

I don't know if the CLR is capable of doing this, but essentially I want to forcibly create an evaluated collection that implements the IEnumerable<T> interface, but is implemented under the hood by the CLR, thus NOT a List<T> or Array<T>

Presumably this is not possible, since I'm not aware of any CLR capability to create in-memory, evaluated collections that implement IEnumerable<T>

Proposal

Say for example, I could write something like this:

var x = IEnumerable<FooBar> fooBars = db.FooBars
        .Where(o => o.SomeValue == something)
        .Evaluate(); // Does NOT return a "concrete" impl such as List<T> or Array<T>

Console.WriteLine(x.GetType().Name);
// eg. <EvaluatedEnumerable>e__123

Solution

  • Is there a way to force an IEnumerable<T> collection to contain results without calling .ToArray() or .ToList(); ?

    Yes, but it is perhaps not what you want:

    IEnumerable<T> source = …;
    IEnumerable<T> cached = new List<T>(source);
    

    The thing is, IEnumerable<T> is not a concrete type. It is an interface (contract) representing an item sequence. There can be any concrete type "hiding behind" this interface; some might only represent a query, others actually hold the queried items in memory.

    If you want to force-evaluate your sequence so that the result is actually stored in physical memory, you need to make sure that the concrete type behind IEnumerable<T> is a in-memory collection that holds the results of the evaluation. The above code example does just that.