我试图了解AsEnumerable()
在迭代它时对我的数据的影响。我有一个模拟内存列表。如果我foreach
首先调用ToList()
,这会强制进行评估,我的打印输出看起来像这样(请参阅本文底部的代码来解释输出):
entering da
yield return
yield return
yield return
exiting da
doing something to aaron
doing something to jeremy
doing something to brendan
一切都有道理。 ToList()
强制存储库中的yield首先执行到列表中,然后我们得到foreach
次迭代。到目前为止都很好。
当我使用AsEnumerable()
时,除了使用IQueryable
之外,基于我所读到的关于IQueryable
的内容(我明白这不是entering da
yield return
doing something to aaron
yield return
doing something to jeremy
yield return
doing something to brendan
exiting da
),我会认为这也是评价,但事实并非如此。它看起来像这样:
AsEnumerable()
如果我从未打过AsEnumerable
,我的问题就是:
为什么IQueryable
对于内存集合与linq到sql及其SqlDataReader
返回类型的行为不同?
当我的存储库更改为使用yield return
并在阅读器内部执行Read()
(同时调用foreach
方法)时,所有这些都会发生变化。在执行yield
之前,来自SqlServer的在客户端网络缓冲区中缓冲的行是否会被完全评估(通常这里foreach
会导致repo中的“暂停”,而每个行都由ToList()
阻止。我知道如果我在这种情况下首先致电SqlDataReader
,我可以强制评估AsEnumerable
,SqlDataReader
也会这样做吗?
注意:我不知道将收益率放到 public class TestClient
{
public void Execute()
{
var data = MockRepo.GetData();
foreach (var p in data.AsEnumerable()) //or .ToList()
{
Console.WriteLine("doing something to {0}", p.Name);
}
Console.ReadKey();
}
}
public class Person
{
public Person(string name)
{
Name = name;
}
public string Name { get; set; }
}
public class MockRepo
{
private static readonly List<Person> items = new List<Person>(3)
{
new Person("aaron"),
new Person("jeremy"),
new Person("brendan")
};
public static IEnumerable<Person> GetData()
{
Console.WriteLine("entering da");
var enumerator = items.GetEnumerator();
while (enumerator.MoveNext())
{
Console.WriteLine("yield return");
yield return enumerator.Current;
}
Console.WriteLine("exiting da");
}
}
是否是一个好主意,因为它可能会保持连接打开,我已经把这个话题打败了:)
这是我的测试代码:
{{1}}
答案 0 :(得分:4)
AsEnumerable
之外, IEnumerable<T>
nothing 除外。当它在这样的查询中使用时:
var query = db.Customers
.Where(x => x.Foo)
.AsEnumerable()
.Where(x => x.Bar);
...这只是意味着你将Queryable.Where
用于第一个谓词(以便转换为SQL),而Enumerable.Where
用于第二个谓词(这样在.NET代码中执行)
它不会强制评估。它没有任何。它甚至不会检查是否在null
上调用它。
有关详细信息,请参阅我的Edulinq blog post on AsEnumerable
。
答案 1 :(得分:1)
@Jon Skeet已经发布了AsEnumerable()
所做的事情 - 它只是改变了编译时间类型。但你为什么要用呢?
基本上,通过将表达式从IQueryable
更改为IEnumerable
,您现在可以使用Linq到对象(而不是数据库提供程序的IQueryable实现),没有任何限制 - 不必是数据库方面的等效方法,因此您可以自由地执行对象转换,远程调用(如果需要)或任何类型的字符串操作。
那就是说当你还在使用数据库(IQueryable
)时你会想要做所有的过滤 - 否则你会把所有这些行都带到内存中,这会耗费你的成本 - 然后才使用AsEnumerable()
之后进行最后的转换。
答案 2 :(得分:0)
AsEnumerable(Of TSource)(IEnumerable(Of TSource))方法没有 效果除了从a更改源代码的编译时类型 将IEnumerable(Of T)实现为IEnumerable(Of T)本身的类型。
它不应该引起任何评估,只是提示您要使用IEnumerable方法与其他一些实现(IQueryable等)。