使用什么? 他们如何工作?

我对Enumerators如何工作以及LINQ有一些疑问。 考虑这两个简单的选择:

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

要么

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

我改变了我的原始对象的名字,这样看起来就像一个更通用的例子。 查询本身并不重要。 我想问的是这样的:

foreach (Animal animal in sel) { /*do stuff*/ }
  • 我注意到,如果我使用IEnumerable ,当我调试并检查“sel”时(它在IEnumerable中),它有一些有趣的成员:“inner”,“outer”,“innerKeySelector”和“outerKeySelector”似乎是代表。 “内部”成员中没有“Animal”实例,而是“Species”实例,这对我来说很奇怪。 “外层”成员确实包含“动物”实例。 我认为这两位代表决定进入哪些内容?

  • 我注意到如果我使用“Distinct”,“inner”包含6个项目(这是不正确的,因为只有2个是Distinct),但是“outer”包含正确的值。 同样,委托方法可能决定了这一点,但这比我对IEnumerable的了解还多一点。

  • 最重要的是,两种选择中的哪一种选择是最好的表现?

  • 通过.ToList()邪恶的列表转换?

    或者可能直接使用枚举器?

    如果可以的话,也请解释一下或者抛出一些解释IEnumerable的使用的链接。


    IEnumerable描述了行为,而List则是该行为的实现。 当你使用IEnumerable ,你给编译器一个延迟工作的机会,直到后来才有可能优化。 如果使用ToList(),则可以强制编译器立即生成结果。

    无论何时“堆叠”LINQ表达式,我都使用IEnumerable ,因为通过只指定行为,我给了LINQ一个延迟评估和可能优化程序的机会。 记住LINQ在枚举之前不会生成SQL来查询数据库? 考虑这个:

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

    现在你有一个方法可以选择一个初始样本(“AllSpotted”)和一些过滤器。 所以现在你可以做到这一点:

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

    那么在IEnumerable上使用List会更快吗? 仅当您想要阻止多次执行查询时。 但是总体来说更好吗? 那么在上面,Leopards和Hyenas每个都被转换成单个SQL查询,而数据库只返回相关的行。 但是如果我们从AllSpotted()返回一个List,那么它可能会运行得更慢,因为数据库可能会返回比实际需要更多的数据,并且我们会浪费循环在客户端进行过滤。

    在一个程序中,最好延迟将查询转换为列表直到最后,所以如果我要不止一次地通过Leopards和Hyenas枚举,我会这样做:

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

    实现IEnumerable的类允许您使用foreach语法。

    基本上它有一种方法来获取集合中的下一个项目。 它不需要整个集合在内存中,也不需要知道其中有多少物品, foreach只是不断得到下一个物品,直到它耗尽。

    在某些情况下,这可能非常有用,例如,在开始处理行之前,您不希望将整个事件复制到内存中的海量数据库表中。

    现在List实现IEnumerable ,但代表了内存中的整个集合。 如果你有一个IEnumerable并且调用.ToList()你可以在内存中创建一个枚举内容的新列表。

    你的linq表达式返回一个枚举,默认情况下,当你使用foreach迭代时,表达式会执行。 迭代foreach时会执行IEnumerable linq语句,但您可以使用.ToList()更快地强制迭代。

    这就是我的意思:

    var things = 
        from item in BigDatabaseCall()
        where ....
        select item;
    
    // this will iterate through the entire linq statement:
    int count = things.Count();
    
    // this will stop after iterating the first one, but will execute the linq again
    bool hasAnyRecs = things.Any();
    
    // this will execute the linq statement *again*
    foreach( var thing in things ) ...
    
    // this will copy the results to a list in memory
    var list = things.ToList()
    
    // this won't iterate through again, the list knows how many items are in it
    int count2 = list.Count();
    
    // this won't execute the linq statement - we have it copied to the list
    foreach( var thing in list ) ...
    

    有一篇非常好的文章:Claudio Bernasconi的TechBlog在这里:何时使用IEnumerable,ICollection,IList和List

    这里有一些关于场景和功能的基础知识点:

    在这里输入图像描述在这里输入图像描述

    链接地址: http://www.djcxy.com/p/4809.html

    上一篇: What to Use? How do they work?

    下一篇: When to use struct?