• LINQ中的陷阱--TakeWhile&SkipWhile


    在用TakeWhile,SkipWhile设置陷阱之前,我们先来看一看他们的兄弟Take和Skip:

    public static IEnumerable<T> Take<T>(IEnumerable<T> source, int count)

    public static IEnumerable<T> Skip<T>(IEnumerable<T> source, int count)

     这两个操作符从字面上看就能理解其含义.Take将枚举出source中的前count个元素,返回给客户端.而Skip 则恰好相反,将跳过source中的前count个元素,枚举其余元素.LINQ内部实现代码十分简单,不用多分析.不过,他们的兄弟TakeWhile 和SkipWhile确埋下了个陷阱,让我小小的摔了一跤.现在,我就来重新布置这个陷阱: 

    考虑如下的数据源:

    static List<Customer> customers = new List<Customer> {
    new Customer { CustomerID=1,Name="woody1"},
    new Customer { CustomerID=2,Name="woody2"},
    new Customer { CustomerID=3,Name="woody3"},
    new Customer { CustomerID=4,Name="woody1"}
    };

     在这个数据源的基础上,我进行了如下操作:

    var cs1 = customers.TakeWhile(c => c.Name == "woody1");
    var cs2 = customers.TakeWhile(c => c.Name == "woody2");
    var cs3 = customers.SkipWhile(c => c.Name == "woody1");
    var cs4 = customers.SkipWhile(c => c.Name == "woody2");

    好了.现在,你能猜得出来cs1--cs4这四个IEnumerable<Customer>变量中都保存着些什么什么元素吗? 
      正确答案是: 
      cs1 : woody1(CustomerID=1) 
      cs2 : 没有任何元素 
      cs3 : woody2 , woody3 , woody1(CustomerID=4) 
      cs4 : woody1(CustomerID=1),woody2,woody3,woody1(CustomerID=4) 
      Surprise?:)反正我是小小的"惊喜"了一下.OK.研究实现代码吧... 
      TakeWhile在LINQ中实现的思想是:对数据源进行枚举,从第一个枚举得到的元素开始,调用客户端传入的predicate( c.Name == ""woodyN"),如果这个predicate委托返回true的话,则将该元素作为Current元素返回给客户端,并且,继续进行相同的枚举,判断操作.但是,一旦predicate返回false的话,MoveNext()方法将会返回false,枚举就此打住,忽略剩下的所有元素
    类似的,SkipWhile也对数据源进行枚举,从第一个枚举得到的元素开始,调用客户端的predicate,如果返回true,则跳过该元素,继续进行枚举操作.但是,如果一旦predicate返回为false,则该元素以后的所有元素,都不会再调用predicate,而全部枚举给客户端. 

    这两个方法总结为:遍历时,检查predicate条件,只要一遇到返回false,就打住,后面的元素不再去检测,直接返回结果。
      (内部实现代码很简单,不再列出) 
      现在,再回头看看陷阱的正确答案,是不是跑出来了呢?:)最开始,我一直以为是LINQ的一个BUG,还打算上LINQ论坛报BUG,不过,后来细想 Take,Skip,再详细阅读了LINQ的文档后,发现似乎这并不是BUG,这就是这两个操作符的正确逻辑.不过,起这样的名字,出这样的结果,实在让人觉得困惑啊~

    完整的控制台程序代码如下:

    class Customer
        {
            public int CustomerID { get; set; }
            public string Name { get; set; }
        }
    
    class Program
        {
            static void Main(string[] args)
            {
                List<Customer> customers = new List<Customer> {
                    new Customer { CustomerID=1,Name="woody1"},
                    new Customer { CustomerID=2,Name="woody2"},
                    new Customer { CustomerID=3,Name="woody3"},
                    new Customer { CustomerID=4,Name="woody1"}
                };      
          
                var cs1 = customers.TakeWhile(c => c.Name == "woody1");
                var cs2 = customers.TakeWhile(c => c.Name == "woody2");
                var cs3 = customers.SkipWhile(c => c.Name == "woody1");
                var cs4 = customers.SkipWhile(c => c.Name == "woody2");
    
                Console.WriteLine("Result One:TakeWhile(c => c.Name == woody1)");
                foreach (var customer in cs1)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Two:TakeWhile(c => c.Name == woody2)");
                foreach (var customer in cs2)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Three:SkipWhile(c => c.Name == woody1)");
                foreach (var customer in cs3)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.WriteLine("Result Four:SkipWhile(c => c.Name == woody2)");
                foreach (var customer in cs4)
                {
                    Console.WriteLine(customer.CustomerID + ":" + customer.Name);
                }
                Console.ReadKey();
    
            }
  • 相关阅读:
    EF CodeFirst下,当实体结构发生修改怎么更新数据库结构 【常用总结】
    基于 ASP.NET Core 的 EF Core 入门
    autofac 一个接口多个实现的情况
    C#中使用HttpClient来Post数据的内容HttpContent的各种格式
    # 使用HttpClient的post,get 封装
    C# 模拟提交带附件(input type=file)的表单
    C#使用HttpClient上传文件并附带其他参数
    2021年总结一下
    PhpStorm+Xdebug断点调试
    PHP数组排序
  • 原文地址:https://www.cnblogs.com/purplefox2008/p/4934426.html
Copyright © 2020-2023  润新知