在用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. MySQL的进程状态

    通过show processlist查看MySQL的进程状态,在State列上面的状态有如下这些: Analyzing线程对MyISAM 表的统计信息做分析(例如, ANALYZE TABLE ).c ...

  2. expr 数字操作

    expr 可以用于计算 [root@rhel6 script]# * * [root@rhel6 script]# 使用expr来判断输入的变量是否为整数, 注意这里的&表示  安静模式(没有 ...

  3. bagging与boosting集成学习、随机森林

    主要内容: 一.bagging.boosting集成学习 二.随机森林 一.bagging.boosting集成学习 1.bagging: 从原始样本集中独立地进行k轮抽取,生成训练集.每轮从原始样本 ...

  4. JavaWeb -- 会话, Cookie 和 Session

    1. 会话 •Cookie是客户端技术,服务器把每个用户的数据以cookie的形式写给用户各自的浏览器.当用户使用浏览器再去访问服务器中的web资源时,就会带着各自的数据去.这样,web资源处理的就是 ...

  5. 大话设计模式--工厂模式 factory -- C++实现实例

    实现<大话设计模式>的C++版本... 1. 工厂模式 使用的范围是 同一个基类,下面很多子类. (1)这里很容易出现的一个问题n多的子类继承自抽象基类,我们不得不在每次要用到子类的地方就 ...

  6. java:类集操作总结

    java:类集操作总结 1.List接口允许有重复的元素,Set接口中不允许有重复的元素 2.ArrayList,和Vector的区别 3.set依靠equals和hashCode区分 4.TreeS ...

  7. wp8使用现有sqlite数据库

    就是把现有文件转移到隔离空间即可 代码如下 private async void CopyDB()        {            StorageFile fage = await Appli ...

  8. JSP的一个增删改查例子和总结

    总结的几点: 1.在jsp中注意<%! %>声明代码块中的变量只会在项目开始的时候第一次运行jsp的时候执行一遍,有点类似于java类中的static代码块,所以如果是会改变的值不应该声明 ...

  9. 实现stack 加上·getMin功能 时间复杂度为O(n)

    package com.hzins.suanfa; import java.util.Stack; /** * 实现stack 加上·getMin功能 时间复杂度为O(n) * @author Adm ...

  10. IO - 同步,异步,阻塞,非阻塞 (转帖:http://blog.csdn.net/historyasamirror/article/details/5778378)

    同步(synchronous) IO和异步(asynchronous) IO,阻塞(blocking) IO和非阻塞(non-blocking)IO分别是什么,到底有什么区别?这个问题其实不同的人给出 ...