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的扩展方法的更多相关文章

  1. .NET中扩展方法和Enumerable(System.Linq)

    LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好,更容易编写,使用起来也超级方便,foreach使循环更加容易,而不 ...

  2. C# IEnumerable与IQueryable ,IEnumerable与IList ,LINQ理解Var和IEnumerable

    原文:https://www.cnblogs.com/WinHEC/articles/understanding-var-and-ienumerable-with-linq.html 使用LINQ从数 ...

  3. IEnumerable和IQueryable和Linq的查询

    IEnumerable和IEnumerable 1.IEnumerable查询必须在本地执行.并且执行查询前我们必须把所有的数据加载到本地.而且更多的时候.加载的数据有大量的数据是我们不需要的无效数据 ...

  4. atitit. 集合groupby 的实现(2)---自定义linq查询--java .net php

    atitit.  集合groupby 的实现(2)---自定义linq查询--java .net php 实现方式有如下 1. Linq的实现原理流程(ati总结) 1 2. groupby  与 事 ...

  5. Linq的Distinct方法的扩展

    原文地址:如何很好的使用Linq的Distinct方法 Person1: Id=1, Name="Test1" Person2: Id=1, Name="Test1&qu ...

  6. ReactiveX 学习笔记(11)对 LINQ 的扩展

    Interactive Extensions(Ix) 本文的主题为对 Ix 库,对 LINQ 的扩展. Buffer Ix.NET Buffer Ix.NET BufferTest Buffer 方法 ...

  7. NHibernate Linq查询 扩展增强 (第九篇)

    在上一篇的Linq to NHibernate的介绍当中,全部是namespace NHibernate命名空间中的IQueryOver<TRoot, TSubType>接口提供的.IQu ...

  8. 【C#夯实】我与接口二三事:IEnumerable、IQueryable 与 LINQ

    序 学生时期,有过小组作业,当时分工一人做那么两三个页面,然而在前端差不多的时候,我和另一个同学发生了争执.当时用的是简单的三层架构(DLL.BLL.UI),我个人觉得各写各的吧,到时候合并,而他觉得 ...

  9. 记录一次源码扩展案列——FastJson自定义反序列化ValueMutator

    背景:曾经遇到一个很麻烦的事情,就是一个json串中有很多占位符,需要替换成特定文案.如果将json转换成对象后,在一个一个属性去转换的话就出出现很多冗余代码,不美观也不是很实用. 而且也不能提前在j ...

随机推荐

  1. HDU 3861 The King’s Problem(强连通分量+最小路径覆盖)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3861 题目大意: 在csdn王国里面, 国王有一个新的问题. 这里有N个城市M条单行路,为了让他的王国 ...

  2. .net/c#常用框架/中间件简介

    任务调度 Quartz.NET:Quartz.NET是一个开源的作业调度框架,非常适合在平时的工作中,定时轮询数据库同步,定时邮件通知,定时处理数据等. Quartz.NET允 许开发人员根据时间间隔 ...

  3. 【LOJ】#2057. 「TJOI / HEOI2016」游戏

    题解 我并不会做,我觉得很像网络流但是毫无建图思路 我猜了个贪心,写了一下--啥过了90分?!这数据是有多水啊.. 哦又是行列拆点 不过要按照'#'进行拆点,也就是一段横着的区间只能放一个炸弹,一段竖 ...

  4. 第一个iOS程序:Hello iOS

    今天我们来创建第一个iOS程序:Hello iOS!不需要写任何代码就能实现:

  5. vue 单向数据流 & 双向绑定

    在react中是单向数据绑定,而在vue中的特色是双向数据绑定.但是其实就我个人的理解是: 其实无论是vue还是react其实还是提倡单向数据流去管理状态,这一点在vuex和redux状态管理器上体现 ...

  6. [leetcode tree]103. Binary Tree Zigzag Level Order Traversal

    Given a binary tree, return the zigzag level order traversal of its nodes' values. (ie, from left to ...

  7. alpha冲刺阶段博客集合

    作业格式 课程名称:软件工程1916|W(福州大学) 作业要求:项目Alpha冲刺(团队) 团队名称: 那周余嘉熊掌将得队 作业目标:作业集合 团队信息: 队员学号 队员姓名 博客地址 备注 2216 ...

  8. iOS 9应用开发教程之使用开关滑块控件以及滚动部署视图

    iOS 9应用开发教程之使用开关滑块控件以及滚动部署视图 使用ios9中的开关.滑块控件 开关和滑块也是用于和用户进行交互的控件.本节将主要讲解这两种控件. ios9开关 开关控件常用来控制某个功能的 ...

  9. win32创建窗口函数(windows程序内部运行机制)

    利用win32创建窗口函数,主要操作步骤为: 1.设计一个窗口类 2.注册窗口类 3.创建窗口 4.显示及窗口更新 5.消息循环 6.窗口过程函数   (1)设计一个窗口类 设计窗口类,这样的类型已经 ...

  10. 使用IIS实现反向代理

    IIS的反向代理是通过ARR模块来完成的,ARR模块需要另外安装,而且只能通过Web PlatForm Installer安装.关于安装来源与步骤,帖子已有很多,不做描述.启用“Application ...