21扩展IEnumerable<T>泛型接口自定义LINQ的扩展方法
LINQ方法实际上是对IEnumerable<TSource>的扩展,如图:

本篇自定义一个MyWhere方法,达到与Where相同的效果。
使用LINQ自带的Where方法
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>(){1, 2, 3};
IEnumerable<int> query = list.Where(x => x%2 == 0);
list.Add(4);
showConsole(query);
Console.ReadKey();
}
private static void showConsole<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
Console.WriteLine(item.ToString());
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结果:

这样的结果符合LINQ的"延迟加载"的特点,虽然是在IEnumerable<int> query = list.Where(x => x%2 == 0)之后为集合添加元素list.Add(4),但直到调用showConsole(query)遍历,查询才真正执行。
自定义一个MyWhere,无延迟加载
□ 首先想到的是对IEnumerable<TSource>的扩展,创建静态方法和静态类。
public static class Extension
{
//Func<TSource, bool>是委托,返回的是bool类型
public static IEnumerable<TSource> MyWhere<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if(source==null) throw new ArgumentException();
if(predicate==null) throw new ArgumentException();
List<TSource> result = new List<TSource>();
foreach (TSource item in source)
{
if (predicate(item))
{
result.Add(item);
}
}
return result;
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
□ 执行主程序
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>(){1, 2, 3};
IEnumerable<int> query = list.MyWhere(x => x % 2 == 0);
list.Add(4);
showConsole(query);
Console.ReadKey();
}
private static void showConsole<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
Console.WriteLine(item.ToString());
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
□ 结果

这样的结果丢掉了LINQ的"延迟加载"的特点,也就是后加元素list.Add(4)之后,没有再对集合进行遍历。
可希望的结果是:
● 后加元素list.Add(4)之后,还需要遍历集合
● 返回结果还是IEnumerable<TSource>类型
于是,想到了Decorator设计模式,使用它能满足以上2个条件。
自定义一个MyWhere,也有延迟加载,使用Decorator设计模式
● 为了返回IEnumerable<TSource>类型,必须让装饰者类实现IEnumerable<T>接口
● 装饰者类最重要的特点是包含目标参数类型的引用
● 为了能遍历,装饰者类内部还包含了一个迭代器
public class WhereDecorator<T> : IEnumerable<T>
{
private IEnumerable<T> list;
private Func<T, bool> predicate;
public WhereDecorator(IEnumerable<T> list, Func<T, bool> predicate)
{
this.list = list;
this.predicate = predicate;
}
public IEnumerator<T> GetEnumerator()
{
return new WhereEnumerator<T>(list, predicate);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return new WhereEnumerator<T>(list, predicate);
}
public class WhereEnumerator<T> : IEnumerator<T>
{
private List<T> innerList;
private int index;
public WhereEnumerator(IEnumerable<T> list, Func<T, bool> predicate)
{
innerList = new List<T>();
index = -1;
foreach (T item in list)
{
if (predicate(item))
{
innerList.Add(item);
}
}
}
public T Current
{
get { return innerList[index]; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { return innerList[index]; }
}
public bool MoveNext()
{
index++;
if (index >= innerList.Count)
{
return false;
}
else
{
return true;
}
}
public void Reset()
{
index = -1;
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
自定义MyWhere中,现在可以使用装饰者类来返回一个实例。
public static class Extension
{
public static IEnumerable<TSource> MyWhere<TSource>(this IEnumerable<TSource> source,
Func<TSource, bool> predicate)
{
if(source==null) throw new ArgumentException();
if(predicate==null) throw new ArgumentException();
return new WhereDecorator<TSource>(source, predicate);
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
主程序中:
class Program
{
static void Main(string[] args)
{
List<int> list = new List<int>(){1, 2, 3};
IEnumerable<int> query = list.MyWhere(x => x % 2 == 0);
list.Add(4);
showConsole(query);
Console.ReadKey();
}
private static void showConsole<T>(IEnumerable<T> list)
{
foreach (T item in list)
{
Console.WriteLine(item.ToString());
}
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
结果:

可见,与LINQ的Where方法返回结果一样。
总结
● 所有的LINQ方法是对IEnumerable<T>的扩展
● 当我们想对方法返回的结果再进行链式操作的时候,装饰者类就包含方法参数类型的引用并返回与该方法相同的类型。
● 这里的装饰者类需要完成遍历,装饰者类必须实现IEnumerable<T>,内部必须存在迭代器实现IEnumerator<T>接口。
21扩展IEnumerable<T>泛型接口自定义LINQ的扩展方法的更多相关文章
- .NET中扩展方法和Enumerable(System.Linq)
LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好,更容易编写,使用起来也超级方便,foreach使循环更加容易,而不 ...
- C# IEnumerable与IQueryable ,IEnumerable与IList ,LINQ理解Var和IEnumerable
原文:https://www.cnblogs.com/WinHEC/articles/understanding-var-and-ienumerable-with-linq.html 使用LINQ从数 ...
- IEnumerable和IQueryable和Linq的查询
IEnumerable和IEnumerable 1.IEnumerable查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大量的数据是我们不需要的无效数据 ...
- atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php
atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php 实现方式有如下 1. Linq的实现原理流程(ati总结) 1 2. groupby 与 事 ...
- Linq的Distinct方法的扩展
原文地址:如何很好的使用Linq的Distinct方法 Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1&qu ...
- ReactiveX 学习笔记(11)对 LINQ 的扩展
Interactive Extensions(Ix) 本文的主题为对 Ix 库,对 LINQ 的扩展. Buffer Ix.NET Buffer Ix.NET BufferTest Buffer 方法 ...
- NHibernate Linq查询 扩展增强 (第九篇)
在上一篇的Linq to NHibernate的介绍当中,全部是namespace NHibernate命名空间中的IQueryOver<TRoot, TSubType>接口提供的.IQu ...
- 【C#夯实】我与接口二三事:IEnumerable、IQueryable 与 LINQ
序 学生时期,有过小组作业,当时分工一人做那么两三个页面,然而在前端差不多的时候,我和另一个同学发生了争执.当时用的是简单的三层架构(DLL.BLL.UI),我个人觉得各写各的吧,到时候合并,而他觉得 ...
- 记录一次源码扩展案列——FastJson自定义反序列化ValueMutator
背景:曾经遇到一个很麻烦的事情,就是一个json串中有很多占位符,需要替换成特定文案.如果将json转换成对象后,在一个一个属性去转换的话就出出现很多冗余代码,不美观也不是很实用. 而且也不能提前在j ...
随机推荐
- 关于URL编码(针对URL含有中文的参数)
http://www.ruanyifeng.com/blog/2010/02/url_encoding.html 一.问题的由来 URL就是网址,只要上网,就一定会用到. 一般来说,URL只能使用英文 ...
- GrideVlew提供点击按钮添加新数据,单击项目修改,长按删除功能
package com.example.wang.myapplication; import android.app.AlertDialog; import android.content.Dialo ...
- 使用VSCode配置简单的vue项目
由于最近要使用的项目框架为前后端分离的,采用的是vue.js+webAPI的形式进行开发的.因为之前我没有接触过vue.js,也只是通过视频文档做了一些简单的练习.今天技术主管说让大家熟悉下VSCod ...
- 使用linux mysql客户端建立表时遇到格式解析的问题
发现在notepad++写好的建表脚本,粘贴到linux客户端后,执行时总是报我的脚本有问题. 我看了又看,发现建表脚本本身是没有问题,问题出在"Tab"键上和注释上边了. 解决办 ...
- pandas使用总结
一.pandas简介 Pandas是基于Numpy开发出的,是一款开放源码的BSD许可的Python库,为Python编程语言提供了高性能,易于使用的数据结构和数据分析工具.Pandas用于广泛的领域 ...
- Ionic Js七:手势事件
1.on-hold 长按的时间是500毫秒. HTML 代码 <button on-hold="onHold()" class="button">长 ...
- bzoj——2127: happiness
2127: happiness Time Limit: 51 Sec Memory Limit: 259 MBSubmit: 2570 Solved: 1242[Submit][Status][D ...
- Codeforces Round #441 (Div. 2, by Moscow Team Olympiad) E. National Property(2-sat)
E. National Property time limit per test 1 second memory limit per test 512 megabytes input standard ...
- OpenGL笔记<4> 数据传递二
Sending data to a shader using uniform Preface 上一节我们介绍了通过顶点属性量进行数据传递,今天我们介绍一下通过uniform变量来进行数据传递的方法. ...
- python获取文件
第一种:使用os.walk: # -*- coding: utf-8 -*- import os def Test1(rootDir): list_dirs = os.walk(rootDir) fo ...