在用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. 双向链表(C++实现)

    ////////////////////////////////////////////////////////////////////////////////////// /////// 这里建立两 ...

  2. JAVA事件监听机制与实现

    事件监听机制的实现:参考图:事件模型_ActionEvent 为了节省资源,系统无法对某个事件进行实时的监听.故实现的机制是当发生某个事件后,处理代码将被自动运行,类似钩子一般.(回调函数) 事件有许 ...

  3. Group By 和 Having, Where ,Order by执行顺序

    1.Group By 和 Having, Where ,Order by这些关键字是按照如下顺序进行执行的:Where, Group By, Having, Order by. 首先where将最原始 ...

  4. UVA 1493 Draw a Mess(并查集+set)

    这题我一直觉得使用了set这个大杀器就可以很快的过了,但是网上居然有更好的解法,orz... 题意:给你一个最大200行50000列的墙,初始化上面没有颜色,接着在上面可能涂四种类型的形状(填充):  ...

  5. 韩顺平Linux

    shutdown -h now 立刻进行关机 shutdown -r now 立即重启 reboot同上. 用户登录尽量少用root账号登录,因为它是系统管理员,最大的管理权限,避免操作失误. 可以利 ...

  6. vue2.0 构建单页应用最佳实战

    vue2.0 构建单页应用最佳实战   前言 我们将会选择使用一些 vue 周边的库vue-cli, vue-router,vue-resource,vuex 1.使用 vue-cli 创建项目2.使 ...

  7. CommonJS、AMD与CMD

    自从有了模块,我们可以更方便地使用别人的代码,想要什么功能,就加载什么模块.但是,这样做有一个前提,那就是大家必须以同样的方式编写模块,否则你有你的写法,我有我的写法,岂不是乱了套! 于是下面三个模块 ...

  8. java:练习学校学生

    java:练习学校学生 一个学生对应一个学校 一个学校对应多个学生 Student类,School类,Demo测试类 Student: public class Student { private S ...

  9. [原创]Java开发在线编辑Word同时实现全文检索

    一.背景介绍 Word文档与日常办公密不可分,在实际应用中,当某一文档服务器中有很多Word文档,假如有成千上万个文档时,用户查找打开包含某些指定关键字的文档就变得很困难,一般情况下能想到的解决方案是 ...

  10. codeforces 615E Hexagons (二分+找规律)

    E. Hexagons time limit per test 1 second memory limit per test 256 megabytes input standard input ou ...