本文介绍了如何判断一个IEnumerable< T>受延迟执行?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我总是假设,如果我用选择(X => ...)在LINQ到对象的上下文,那么新的集合将立即创建并保持不变。我不明白为什么我以为这和它的一个非常坏的假设,但我做到了。我经常使用 .ToList()其他地方,但往往不是在这种情况下。



此代码演示,即使是简单的选择受延迟执行:

  VAR随机=新的随机(); 
变种动物=新[] {猫,狗,老鼠};
变种randomNumberOfAnimals = animals.Select(X => Math.Floor(random.NextDouble()* 100)++ X +的s);

的foreach(VAR我在randomNumberOfAnimals)
{
testContextInstance.WriteLine(有+ I);
}

的foreach(VAR我在randomNumberOfAnimals)
{
testContextInstance.WriteLine(现在,有+ I);
}

这输出以下(随机函数被调用每一个集合的迭代时间通过):

 有75猫
有28个狗
有62鼠标
和现在,还有78只猫
而现在,有69个狗
而现在,有43个鼠标

我有很多地方我有一个的IEnumerable< T> 作为一个类的成员。通常,LINQ查询的结果被分配到这样的的IEnumerable< T> 。通常,对我来说这不会造成问题,但我最近发现我的代码它带来的不仅仅是性能问题更加的几个地方。



在试图检查在那里我做了这样的错误,我想我可以检查的地方如果一个特定的的IEnumerable< T> 是类型的IQueryable 。这一点,我想会告诉我,如果集合是'推迟'与否。事实证明,通过上述选择运营商创建的枚举类型是 System.Linq.Enumerable + WhereSelectArrayIterator`` [System.String,System.String] ,而不是<$的C $ C>的IQueryable 。



我用的来看看来自继承了这个接口,和原来不从任何表明它是LINQ在所有的继承 - 所以没有办法根据集合类型测试

我很愉快,现在把 .ToArray()现在到处都是,但我想有一个机制确保在今后的犯规发生这个问题。 Visual Studio中似乎知道如何,因为它提供了有关消息做



我想出的最好的'扩大结果视图将评估集合。:

 布尔递延= object.ReferenceEquals(randomNumberOfAnimals.First(),
randomNumberOfAnimals.First())!;



编辑:仅在一个新的对象与创建该作品的选择它不是一个通用的解决方案。我不是在任何情况下推荐它虽然!这是一个解决方案的脸颊小舌头。


解决方案

LINQ的延迟执行已被困了很多人,你。不是一个人



我已经采取了避免这个问题的方法如下:



参数方法的 - 使用的IEnumerable< T> 除非有需要更具体的接口



局部变量的 - 通常在那里我创建了LINQ的地步,所以我就知道偷懒评估是否可能



类成员的 - 从来没有使用的IEnumerable< T> ,总是用列表< T> 。 。总是让他们的私人



属性的 - 使用的IEnumerable< T> 和。转换为存储在二传手

 公开的IEnumerable<&人GT;人们
{
{返回万人; }
集合{=人value.ToList(); }
}
私有列表<人与GT;人;



虽然有理论的情况下,这种做法是行不通的,我没有跑成一个尚未,我一直在用热情地下旬以来的贝塔LINQ扩展方法



BTW:为什么你用我很好奇 ToArray的(); 而不是了ToList(); - 对我来说,名单有一个更加美好的API,并有(几乎)没有任何性能开销



更新:一对夫妇评论者都正确地指出,阵列具有理论上的性能优势,所以我修改上面我的发言...有(几乎)没有任何性能开销



更新2 :我写了一些代码,做差价的一些微基准测试在阵列之间的性能和列表。在我的笔记本电脑,在我的具体性能指标评测,所不同的是周围的5ns每次访问(这是的纳米的秒)。我想有这样的情况:每个回路节电5ns的将是值得的......但我从来没有碰到过的。我不得不加息我的测试高达100的亿的运行之前迭代成为足够长的精确测量。


I always assumed that if I was using Select(x=> ...) in the context of LINQ to objects, then the new collection would be immediately created and remain static. I'm not quite sure WHY I assumed this, and its a very bad assumption but I did. I often use .ToList() elsewhere, but often not in this case.

This code demonstrates that even a simple 'Select' is subject to deferred execution :

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);
}

This outputs the following (the random function is called every time the collection is iterated through):

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

I have many places where I have an IEnumerable<T> as a member of a class. Often the results of a LINQ query are assigned to such an IEnumerable<T>. Normally for me this does not cause issues, but I have recently found a few places in my code where it poses more than just a performance issue.

In trying to check for places where I had made this mistake I thought I could check to see if a particular IEnumerable<T> was of type IQueryable. This i thought would tell me if the collection was 'deferred' or not. It turns out that the enumerator created by the Select operator above is of type System.Linq.Enumerable+WhereSelectArrayIterator``[System.String,System.String] and not IQueryable.

I used Reflector to see what this interface inherited from, and it turns out not to inherit from anything that indicates it is 'LINQ' at all - so there is no way to test based upon the collection type.

I'm quite happily now putting .ToArray() everywhere now, but I'd like to have a mechanism to make sure this problem doesnt happen in future. Visual Studio seems to know how to do it because it gives a message about 'expanding the results view will evaluate the collection.'

The best I have come up with is :

bool deferred = !object.ReferenceEquals(randomNumberOfAnimals.First(),
                                        randomNumberOfAnimals.First());

Edit: This only works if a new object is created with 'Select' and it not a generic solution. I'm not recommended it in any case though! It was a little tongue in cheek of a solution.

解决方案

Deferred execution of LINQ has trapped a lot of people, you're not alone.

The approach I've taken to avoiding this problem is as follows:

Parameters to methods - use IEnumerable<T> unless there's a need for a more specific interface.

Local variables - usually at the point where I create the LINQ, so I'll know whether lazy evaluation is possible.

Class members - never use IEnumerable<T>, always use List<T>. And always make them private.

Properties - use IEnumerable<T>, and convert for storage in the setter.

public IEnumerable<Person> People 
{
    get { return people; }
    set { people = value.ToList(); }
}
private List<People> people;

While there are theoretical cases where this approach wouldn't work, I've not run into one yet, and I've been enthusiasticly using the LINQ extension methods since late Beta.

BTW: I'm curious why you use ToArray(); instead of ToList(); - to me, lists have a much nicer API, and there's (almost) no performance cost.

Update: A couple of commenters have rightly pointed out that arrays have a theoretical performance advantage, so I've amended my statement above to "... there's (almost) no performance cost."

Update 2: I wrote some code to do some micro-benchmarking of the difference in performance between Arrays and Lists. On my laptop, and in my specific benchmark, the difference is around 5ns (that's nanoseconds) per access. I guess there are cases where saving 5ns per loop would be worthwhile ... but I've never come across one. I had to hike my test up to 100 million iterations before the runtime became long enough to accurately measure.

这篇关于如何判断一个IEnumerable&LT; T&GT;受延迟执行?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

10-29 13:55