C# LINQ中的Where方法的内部实现
写C#快一年多了,今天在b站搜到一个进阶的课程,打算提高一些自己的水平,然后就开始学习了。课程讲的是我平时开发过程中用的最多的LINQ内部实现和实际运行过程剖析,我会把每节课程的学习内容写成博客记录下来,只为了记录自己的学习和成长过程,如果有人能够从中受益,那我是更加开心啦。
引子:
假设我们有一个0-10的数组,需要挑出所有的奇数,那么我们就可以用Where语句来过滤出满足条件的数字
var items=new []{1,2,3,4,5,6,7,8,9,10};
var evenNums=items.Where(x=>x%2==0);
foreach(var item in evenNums)
{
Console.WriteLine(item);
}
上面的代码可以让我们实现这个需求
但是如果我们在Where的下面一句代码上打一个断点,此时我们发现evenNums里面其实并没有把我们需要的奇数过滤出来,此时的变量evenNums是空的,Where的过滤这步操作其实是到foreach遍历的时才执行的。
下面我们可以自己实现一个Where的功能来看一下效果
using System;
using System.Collections.Generic;
namespace cSharp_Application
{
public static class IEnumerableExtension
{
public static IEnumerable<T> NewWhere<T>(this IEnumerable<T> items,Func<T,bool> predicate)
{
List<T> data=new List<T>();
foreach(var item in items)
{
if(predicate(item))
{
data.Add(item);
}
}
return data;
}
}
}
用我自己实现的NewWhere去替换LINQ本身的Where以后,可以惊喜的发现,同样的evenNums,现在在执行完下面的一句代码时,已经把需要过滤的条件的过滤出来了,说明LINQ本身的实现方式与我现在的实现是有区别的。从官方文档和比较权威的博客那边的解释是说,LINQ的这种处理方式是一种延迟执行,也就是到了需要取数据时采取执行的
var evenNums=items.NewWhere(x=>x%2==0);
那么如何自己实现这种延迟执行的效果呢???
我们可以把实现NewWhere的代码再仔细看一下
using System;
using System.Collections.Generic;
namespace cSharp_Application
{
public static class IEnumerableExtension
{
public static IEnumerable<T> NewWhere<T>(this IEnumerable<T> items,Func<T,bool> predicate)
{
List<T> data=new List<T>();
foreach(var item in items)
{
if(predicate(item))
{
data.Add(item);
}
}
return data;
}
}
}
上面的代码有一个return语句,问题就出在这个return关键字上。
如果我们用下面的方式,配合IEnumerable接口和yield关键字
using System;
using System.Collections.Generic;
namespace cSharp_Application
{
public static class IEnumerableExtension
{
public static IEnumerable<T> NewWhere<T>(this IEnumerable<T> items,Func<T,bool> predicate)
{
//List<T> data=new List<T>();
foreach(var item in items)
{
if(predicate(item))
{
//data.Add(item);
yield return item;
}
}
//return data;
}
}
}
此时,我们自己实现的NewWhere语句也实现了延迟执行的特性
虽然我现在还不知道,微软为什么要设计成这种延迟执行的方式,但是我觉得他这样设计肯定有他自己的理由,说不定就这样子一点点的学习到某个阶段,我就能理解他这么设计的原因了吧。有朝一日我知道了,这么设计的原因时,我会回来更新博客。