且构网

分享程序员开发的那些事...
且构网 - 分享程序员编程开发的那些事

IEnumerable的VS列表 - 怎么使用?他们如何工作?

更新时间:2023-11-22 23:11:22

的IEnumerable 描述的行为,而名单是该行为的实现。当您使用的IEnumerable ,你给编译器有机会推迟工作,直到后来,可能是沿途的优化。如果你使用了ToList()您强制编译器具体化的结果的时候了。

每当我堆积LINQ前pressions,我用的IEnumerable ,因为只有指定的行为,我给LINQ有机会推迟评估,并可能优化方案。记住LINQ怎么不生成SQL,直到你枚举它来查询数据库?试想一下:

 公开的IEnumerable<动物> AllSpotted()
{
    从在Zoo.Animals返回
           其中,a.coat.HasSpots ==真
           选择一个;
}公共IEnumerable的<动物>猫(IEnumerable的<动物>样品)
{
    从样品返回
           其中,a.race.Family ==猫科动物
           选择一个;
}公共IEnumerable的<动物>犬(IEnumerable的<动物>样品)
{
    从样品返回
           其中,a.race.Family ==犬科
           选择一个;
}

现在你有一个选择初始样本(AllSpotted),再加上一些过滤器的方法。所以现在你可以这样做:

  VAR豹猫=(AllSpotted());
变种鬣狗=犬(AllSpotted());

因此​​,它是快了的IEnumerable 使用List?只有当你想prevent被执行多次的查询。但它是更好的整体?在上面,豹子和鬣狗顺利拿到转化成的单个的SQL查询每个的,并且数据库仅返回相关的行。但是,如果我们从 AllSpotted(),那么它可能运行慢,因为该数据库可以返回更多的数据比实际需要的,我们浪费的周期做过滤返回列表在客户端

在一个程序中,它可能是更好推迟查询转换为一个列表,直到最后一刻,所以如果我经历豹子和鬣狗列举不止一次,我会做到这一点:

 列表<动物>豹=猫(AllSpotted())了ToList();
清单<动物>鬣狗=犬(AllSpotted())了ToList();

I have some doubts over how Enumerators work, and LINQ. Consider these two simple selects:

List<Animal> sel = (from animal in Animals 
                    join race in Species
                    on animal.SpeciesKey equals race.SpeciesKey
                    select animal).Distinct().ToList();

or

IEnumerable<Animal> sel = (from animal in Animals 
                           join race in Species
                           on animal.SpeciesKey equals race.SpeciesKey
                           select animal).Distinct();

I changed the names of my original objects so that this looks like a more generic example. The query itself is not that important. What I want to ask is this:

foreach (Animal animal in sel) { /*do stuff*/ }

  1. I noticed that if I use IEnumerable, when I debug and inspect "sel", which in that case is the IEnumerable, it has some interesting members: "inner", "outer", "innerKeySelector" and "outerKeySelector", these last 2 appear to be delegates. The "inner" member does not have "Animal" instances in it, but rather "Species" instances, which was very strange for me. The "outer" member does contain "Animal" instances. I presume that the two delegates determine which goes in and what goes out of it?

  2. I noticed that if I use "Distinct", the "inner" contains 6 items (this is incorrect as only 2 are Distinct), but the "outer" does contain the correct values. Again, probably the delegated methods determine this but this is a bit more than I know about IEnumerable.

  3. Most importantly, which of the two options is the best performance-wise?

The evil List conversion via .ToList()?

Or maybe using the enumerator directly?

If you can, please also explain a bit or throw some links that explain this use of IEnumerable.

IEnumerable describes behavior, while List is an implementation of that behavior. When you use IEnumerable, you give the compiler a chance to defer work until later, possibly optimizing along the way. If you use ToList() you force the compiler to reify the results right away.

Whenever I'm "stacking" LINQ expressions, I use IEnumerable, because by only specifying the behavior I give LINQ a chance to defer evaluation and possibly optimize the program. Remember how LINQ doesn't generate the SQL to query the database until you enumerate it? Consider this:

public IEnumerable<Animals> AllSpotted()
{
    return from a in Zoo.Animals
           where a.coat.HasSpots == true
           select a;
}

public IEnumerable<Animals> Feline(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Felidae"
           select a;
}

public IEnumerable<Animals> Canine(IEnumerable<Animals> sample)
{
    return from a in sample
           where a.race.Family == "Canidae"
           select a;
}

Now you have a method that selects an initial sample ("AllSpotted"), plus some filters. So now you can do this:

var Leopards = Feline(AllSpotted());
var Hyenas = Canine(AllSpotted());

So is it faster to use List over IEnumerable? Only if you want to prevent a query from being executed more than once. But is it better overall? Well in the above, Leopards and Hyenas get converted into single SQL queries each, and the database only returns the rows that are relevant. But if we had returned a List from AllSpotted(), then it may run slower because the database could return far more data than is actually needed, and we waste cycles doing the filtering in the client.

In a program, it may be better to defer converting your query to a list until the very end, so if I'm going to enumerate through Leopards and Hyenas more than once, I'd do this:

List<Animals> Leopards = Feline(AllSpotted()).ToList();
List<Animals> Hyenas = Canine(AllSpotted()).ToList();