Sim*_*ver 28 c# linq linq-to-entities
我总是假设如果我Select(x=> ...)
在LINQ对象的上下文中使用,那么新的集合将立即创建并保持静态.我不太清楚为什么我这么想,这是一个非常糟糕的假设,但我做到了.我经常.ToList()
在其他地方使用,但在这种情况下通常不会.
此代码演示即使是简单的"选择"也会延迟执行:
var random = new Random();
var animals = new[] { "cat", "dog", "mouse" };
var randomNumberOfAnimals = animals.Select(x => Math.Floor(random.NextDouble() * 100) + " " + x + "s");
foreach (var i in randomNumberOfAnimals)
{
testContextInstance.WriteLine("There are " + i);
}
foreach (var i in randomNumberOfAnimals)
{
testContextInstance.WriteLine("And now, there are " + i);
}
Run Code Online (Sandbox Code Playgroud)
这将输出以下内容(每次迭代集合时都会调用随机函数):
There are 75 cats
There are 28 dogs
There are 62 mouses
And now, there are 78 cats
And now, there are 69 dogs
And now, there are 43 mouses
Run Code Online (Sandbox Code Playgroud)
我有很多地方,我有IEnumerable<T>
一个班级的成员.通常,LINQ查询的结果被分配给这样的IEnumerable<T>
.通常对我来说这不会引起问题,但我最近在我的代码中找到了一些不仅仅是性能问题的地方.
在试图检查我犯了这个错误的地方时,我想我可以查看某个特定IEnumerable<T>
的类型IQueryable
.我想这会告诉我收藏是否"延期".事实证明,上面的Select运算符创建的枚举器是类型System.Linq.Enumerable+WhereSelectArrayIterator``[System.String,System.String]
而不是IQueryable
.
我使用Reflector来查看这个接口继承了什么,结果是没有继承任何表明它是'LINQ'的东西 - 所以没有办法根据集合类型进行测试.
我现在很高兴现在.ToArray()
到处都是,但是我希望有一个机制来确保将来这个问题不会发生.Visual Studio似乎知道如何做到这一点,因为它提供了一条关于"扩展结果视图将评估集合"的消息.
我想出的最好的是:
bool deferred = !object.ReferenceEquals(randomNumberOfAnimals.First(),
randomNumberOfAnimals.First());
Run Code Online (Sandbox Code Playgroud)
编辑:这仅适用于使用"选择"创建新对象且不是通用解决方案的情况.不过我不推荐它!这是解决方案的一个小舌头.
Bev*_*van 19
延迟执行LINQ已经困住了很多人,你并不孤单.
我为避免这个问题采取的方法如下:
方法的参数 - IEnumerable<T>
除非需要更具体的接口,否则使用.
局部变量 - 通常在我创建LINQ的时候,所以我会知道是否可以进行惰性求值.
班级成员 - 永远不要使用IEnumerable<T>
,永远使用List<T>
.并始终将它们设为私有.
属性 - IEnumerable<T>
在setter中使用和转换存储.
public IEnumerable<Person> People
{
get { return people; }
set { people = value.ToList(); }
}
private List<People> people;
Run Code Online (Sandbox Code Playgroud)
虽然有理论上这种方法不起作用,但我还没有遇到过这种方法,而且自从Beta版本以来我一直热衷于使用LINQ扩展方法.
顺便说一句:我很好奇为什么你使用ToArray();
而不是ToList();
- 对我来说,列表有一个更好的API,并且(几乎)没有性能成本.
更新:一些评论者正确地指出阵列具有理论上的性能优势,因此我将上面的陈述修改为"......几乎没有性能成本."
更新2:我写了一些代码来对数组和列表之间的性能差异进行一些微基准测试.在我的笔记本电脑上,在我的特定基准测试中,每次访问的差异大约为5ns(即纳秒).我想有些情况下每个循环节省5ns是值得的......但我从未遇到过.在运行时变得足够长以准确测量之前,我不得不将我的测试加入到1 亿次迭代.
一般来说,我会说你应该尽量避免担心是否推迟.
流的执行性质有其优点IEnumerable<T>
.这是真的-有次,这是不利的,但我建议你只是一直处理这些(罕见)次特别-要么去ToList()
或ToArray()
将其转换为一个列表或数组作为适当.
剩下的时间,最好让它延期.需要经常检查这似乎是一个更大的设计问题...
归档时间: |
|
查看次数: |
10201 次 |
最近记录: |