在用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=,Name="woody1"},
new Customer { CustomerID=,Name="woody2"},
new Customer { CustomerID=,Name="woody3"},
new Customer { CustomerID=,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=,Name="woody1"},
new Customer { CustomerID=,Name="woody2"},
new Customer { CustomerID=,Name="woody3"},
new Customer { CustomerID=,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(); }

LINQ中的陷阱--TakeWhile&SkipWhile的更多相关文章

  1. Linq中Take、TakeWhile、Skip、SkipWhile的比较(转)

    参考文章:http://blog.csdn.net/lxfzgg/article/details/20534281 Take() , , , , , , , , , }; ); //从第一个元素开始, ...

  2. LInq之Take Skip TakeWhile SkipWhile Reverse Union Concat 用法

    废话不多说,直接上代码,代码有注释!自行运行测试! class Program { static void Main(string[] args) { string[] names = { " ...

  3. Linq中关键字的作用及用法

    Linq中关键字的作用及用法 1.All:确定序列中的所有元素是否都满足条件.如果源序列中的每个元素都通过指定谓词中的测试,或者序列为空,则为 true:否则为 false. Demo: 此示例使用 ...

  4. Entity Framework 6 Recipes 2nd Edition(11-9)译 -> 在LINQ中使用规范函数

    11-9. 在LINQ中使用规范函数 问题 想在一个LINQ查询中使用规范函数 解决方案 假设我们已经有一个影片租赁(MovieRental )实体,它保存某个影片什么时候租出及还回来,以及滞纳金等, ...

  5. Entity Framework 6 Recipes 2nd Edition(11-11)译 -> 在LINQ中调用数据库函数

    11-11. 在LINQ中调用数据库函数 问题 相要在一个LINQ 查询中调用数据库函数. 解决方案 假设有一个任命(Appointment )实体模型,如Figure 11-11.所示, 我们想要查 ...

  6. 关于Linq中的Lambda表达式中OrderBy的深入理解

    起因:就是一段Linq语句,OrderBy里面的i是什么? IQueryable<Student> slist = (from s in EFDB.Student select s). O ...

  7. Linq 中按照多个值进行分组(GroupBy)

    Linq 中按照多个值进行分组(GroupBy) .GroupBy(x => new { x.Age, x.Sex }) group emp by new { emp.Age, emp.Sex ...

  8. Linq 中的 left join

    Linq 中的 left join 表A User: 表B UserType: Linq: from t in UserType join u in User on t.typeId equal u. ...

  9. LINQ中的一些查询语句格式

    LINQ的基本格式如下所示:var <变量> = from <项目> in <数据源> where <表达式> orderby <表达式> ...

随机推荐

  1. 【leetcode刷题笔记】Insertion Sort List

    Sort a linked list using insertion sort. 题解:实现链表的插入排序. 要注意的地方就是,处理链表插入的时候尽量往当前游标的后面插入,而不要往前面插入,后者非常麻 ...

  2. inline 元素的特性

    http://www.maxdesign.com.au/articles/inline/ http://www.w3.org/TR/CSS2/visuren.html#inline-boxes htt ...

  3. 浏览器对同一IP的最大并发请求数记录

    转载自http://www.iefans.net/liulanqi-zuida-bingfa-lianjieshu/,以方便查阅 版本 HTTP 1.0 服务器(宽带连接) HTTP 1.1 服务器( ...

  4. 对类型化数组(Typed Array)与ArrayBuffer的理解 转囧囧

    类型化数组(Typed Array)也是HTML5中新引入的API.用一句话解释类型化数组就是:它是JS操作二进制数据的接口. 众所周知,直接操作二进制数据可以使程序更为高效, 尽管JS对常规数组做了 ...

  5. 剑指offer之 旋转数组的最小数字

    package Problem8; public class MinInReversingList { /* * 题目描述:把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转. * 输入 ...

  6. 基于js的网页换肤(不需要刷新整个页面,只需替换css文件)

    1. [代码][JS]代码    <HTML><HEAD><link ID="skin" rel="stylesheet" typ ...

  7. adb命令(二)

    1.获取手机型号指令 adb shell cat /system/build.prop | findstr "ro.product.model" 2.获取手机处理器信息 adb s ...

  8. linux命令学习笔记(21):find命令之xargs

    xargs是一条Unix和类Unix操作系统的常用命令.它的作用是将参数列表转换成小块分段传递给其他命令,以避免参数列表过长的问题 xargs的作用一般等同于大多数Unix shell中的反引号,但更 ...

  9. GridView有用的小方法--2017年2月13日

    原文:http://blog.csdn.net/21aspnet/article/category/285354更多:http://blog.csdn.net/21aspnet/article/cat ...

  10. 【LeetCode】010. Regular Expression Matching

    Implement regular expression matching with support for '.' and '*'. '.' Matches any single character ...