强制IEnumerable <T>进行评估而不调用.ToArray()或.ToList()

ser*_*0ne 6 c# linq ienumerable entity-framework lazy-evaluation

如果我使用这样的东西查询EF ...

IEnumerable<FooBar> fooBars = db.FooBars.Where(o => o.SomeValue == something);
Run Code Online (Sandbox Code Playgroud)

IIRC,这在后台创建了一个懒惰评估,可迭代的状态机,但尚未包含任何结果; 相反,它包含一个表达式"如何"在需要时获得结果.

如果我想强制集合包含我必须调用的结果.ToArray().ToList()

有没有办法强制IEnumerable<T>集合包含结果而不调用.ToArray().ToList();

合理

我不知道,如果CLR能够这样做的,但本质上我想强行建立一个评估集合,实现了IEnumerable<T>接口,而是由CLR引擎盖下实现的,因而不是一个List<T>Array<T>

大概这是不可能的,因为我不知道任何CLR功能来创建实现内存的,评估的集合 IEnumerable<T>

提案

比方说,我可以这样写:

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
Run Code Online (Sandbox Code Playgroud)

sta*_*ica 7

有没有办法强制IEnumerable<T>集合包含结果而不调用.ToArray().ToList();

是的,但它可能不是你想要的:

IEnumerable<T> source = …;
IEnumerable<T> cached = new List<T>(source);
Run Code Online (Sandbox Code Playgroud)

问题是,IEnumerable<T>不是具体类型.它是表示项目序列的接口(契约).可以有任何具体类型"隐藏"此界面; 有些可能只代表查询,有些实际上只是在内存中保存查询的项目.

如果要强制评估序列以使结果实际存储在物理内存中,则需要确保后面的具体类型IEnumerable<T>是包含评估结果的内存中集合.上面的代码示例就是这样做的.

  • 值得指出的是,这是除了引擎之外的`.ToList()`方法的实际实现. (5认同)

Sal*_*ari 5

您可以使用foreach循环:

foreach (var item in fooBars) { }
Run Code Online (Sandbox Code Playgroud)

请注意,这会评估中的所有项目fooBars,但会立即丢弃结果。下次您运行相同的foreach循环或时.ToArray().ToList()将再次评估可枚举。

  • @ user3185569:如果我们非常学究,那么可以做到:除了`.ToList()`和`.ToArray()`之外,还有很多方法可以创建内存中的集合。例如,您可以使用常量键选择器调用`.ToLookup()`。或者,您可以使用`new List &lt;T&gt;(…)`。或者,您可以实现自己的集合类型并将其转换为该类型。如果我们不那么学究,那您是对的:评估一个IEnumerable &lt;T&gt;以使其“包含其结果”需要某种(通常在内存中)持久性,这就是集合的目的,所以如果他们是不允许的,那么这变得不可能。 (2认同)