LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好,更容易编写,使用起来也超级方便,foreach使循环更加容易,而不用for int..,linq用起来那么爽,那么linq内部是如何实现的?我们如何自定义linq?我们这里说的linq不是from score in scores  where score > 80 select score;而是System.Linq哦。了解Ling之前先要了解扩展方法,因为linq的实质还是扩展方法。

扩展方法

扩展方法使你能够向现有类型“添加”方法,而无需创建新的派生类型、重新编译或以其他方式修改原始类型。 扩展方法是一种特殊的静态方法,但可以像扩展类型上的实例方法一样进行调用。

例如:

namespace ExtensionMethods
{
public static class MyExtensions
{
public static int WordCount(this string str)
{
return str.Split(new char[] { ' ', '.', '?' },
StringSplitOptions.RemoveEmptyEntries).Length;
}
}
}
//添加引用
using ExtensionMethods;
//使用
string s = "Hello Extension Methods";
int i = s.WordCount();

微软扩展方法建议

微软MSDN上的建议:通常,建议只在不得已的情况下才实现扩展方法,并谨慎地实现。只要有可能,都应该通过创建从现有类型派生的新类型来达到这一目的。

扩展方法建议

1. 当功能与扩展类型最相关时,可以考虑使用扩展方法。
2. 当对第三方库进行扩充的时候,可以考虑使用扩展方法。
3. 当您不希望将某些依赖项与扩展类型混合使用时,可以使用扩展方法来实现关注点分离。
4. 如果不确定到底使用还是不使用扩展方法,那就不要用。

扩展方法是C#语言的一个很好的补充,她使我们能够编写更好,更容易读的代码,但是也应该小心使用,不恰当的使用扩展方法可能导致可读性降低,使测试困难,容易出错。

System.Linq

System.Linq用起来那么好,她内部是如何实现的,当然是查看源码了。

Where源码

public static IEnumerable<TSource> Where<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate) {
if (source == null) throw Error.ArgumentNull("source");
if (predicate == null) throw Error.ArgumentNull("predicate");
if (source is Iterator<TSource>) return ((Iterator<TSource>)source).Where(predicate);
if (source is TSource[]) return new WhereArrayIterator<TSource>((TSource[])source, predicate);
if (source is List<TSource>) return new WhereListIterator<TSource>((List<TSource>)source, predicate);
return new WhereEnumerableIterator<TSource>(source, predicate);
}

这个方法就是一个扩展方法,对数据进行了处理,具体的处理都是在对象中的MoveNext中

public override bool MoveNext() {
if (state == ) {
while (index < source.Length) {
TSource item = source[index];
index++;
if (predicate(item)) {
current = item;
return true;
}
}
Dispose();
}
return false;
}

可以看出就是一个循环处理,如果你觉得还是不清楚,可以看WhereIterator方法

static IEnumerable<TSource> WhereIterator<TSource>(IEnumerable<TSource> source, Func<TSource, int, bool> predicate) {
int index = -;
foreach (TSource element in source) {
checked { index++; }
if (predicate(element, index)) yield return element;
}
}

这下明白了,linq就是扩展方法,对数据进行处理,返回所需要的数据,知道了原理之后,可以写自己的linq扩展方法了。
我想写一个带有控制台输出的Where扩展方法

public static IEnumerable<TSource> WhereWithLog<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate)
{
if (source == null)
{
throw new ArgumentNullException("source", "不能为空");
} if (predicate == null)
{
throw new ArgumentNullException("predicate", "不能为空");
} int index = ;
foreach (var item in source)
{
Console.WriteLine($"Where item:{item},结果:{predicate(item)}");
if (predicate(item))
{
yield return item;
}
index++;
}
}

实现一个打乱数据的扩展方法,这里的方法用了约束,只能是值类型。

public static IEnumerable<T> ShuffleForStruct<T>(this IEnumerable<T> source) where T : struct
{
if (source == null)
throw new ArgumentNullException("source", "不能为空"); var data = source.ToList();
int length = data.Count() - ;
for (int i = length; i > ; i--)
{
int j = rd.Next(i + );
var temp = data[j];
data[j] = data[i];
data[i] = temp;
} return data;
}

到此为止是不是觉得Enumerable中的方法也就是那么回事,没有那么难,我也可以实现。

应评论的需要增加whereif,条件为true执行左边的条件,false执行右边的条件,例如:data.WhereIf(x => x > 5, x => x + 10, x => x - 10)

public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, Func<TSource,bool> predicate, Func<TSource, TSource> truePredicate, Func<TSource, TSource> falsePredicate)
{
if (source == null)
{
throw new ArgumentNullException("source", "不能为空");
} if (predicate == null)
{
throw new ArgumentNullException("predicate", "不能为空");
} if (truePredicate == null)
{
throw new ArgumentNullException("truePredicate", "不能为空");
} if (falsePredicate == null)
{
throw new ArgumentNullException("falsePredicate", "不能为空");
} foreach (var item in source)
{
if (predicate(item))
{
yield return truePredicate(item);
}
else {
yield return falsePredicate(item);
}
}
}

或者简单的whereif,true执行条件,false不执行,例如:data.WhereIf(x => x > 5,true)

public static IEnumerable<TSource> WhereIf<TSource>(this IEnumerable<TSource> source, Func<TSource, bool> predicate, bool condition)
{
return condition ? source.Where(predicate) : source;
}

其他的linq文章

1. Linq的执行效率及优化

2. C#中linq

.NET中扩展方法和Enumerable(System.Linq)的更多相关文章

  1. 扩展方法和Enumerable

    .NET中扩展方法和Enumerable(System.Linq) LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好 ...

  2. 【转载】.NET(C#): Task.Unwrap扩展方法和async Lambda

    .NET(C#): Task.Unwrap扩展方法和async Lambda 目录 Task.Unwrap基本使用 Task.Factory.StartNew和Task.Run的Unwrap操作 使用 ...

  3. 线程中sleep方法和wait方法有什么区别?(转)

    本文转自https://www.cnblogs.com/linkstar/p/6043846.html 线程中sleep方法和wait方法有什么区别?   如果你没有接触过java的多线程,那么多对于 ...

  4. Classloader中loadClass()方法和Class.forName()区别

    Classloader中loadClass()方法和Class.forName()都能得到一个class对象,那这两者得到的class对象有什么区别呢 1.java类装载的过程 Java类装载有三个步 ...

  5. Hibernate中evict方法和clear方法说明

    Hibernate中evict方法和clear方法说明 先创建一个对象,然后调用session.save方法,然后调用evict方法把该对象清除出缓存,最后提交事务.结果报错: Exception i ...

  6. ThinkPHP 中M方法和D方法详解----转载

    转载的地址,http://blog.163.com/litianyichuanqi@126/blog/static/115979441201223043452383/ 自己学到这里的时候,不能清除的分 ...

  7. ThinkPHP 中M方法和D方法的具体区别(转)

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  8. ThinkPHP 中M方法和D方法的具体区别

    M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...

  9. jquery中prop()方法和attr()方法

    接着上一篇笔记的疑惑,找了下prop()方法和attr()方法的区别. 原来query1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. ...

随机推荐

  1. android仿新浪引导界面

    最近在研究如何做出仿微信,仿新浪等应用,第一次安装使用的使用展示应用程序的新特性和用法. 实现功能:左右手势滑屏 底部小圆点随当前显示页跳动 浮动按钮显示.当触屏事件发生显示,否则就渐渐消失 先转个文 ...

  2. qemu使用copy-on-write(COW)磁盘

    写时复制(copy-on-write,缩写COW)技术不会对原始的镜像文件做更改,变化的部分写在另外的镜像文件中,这种特性在qemu中只有QCOW格式支持,多个 COW 文件可以指向同一映像同时测试多 ...

  3. redis 学习笔记——持久化

    redis持久化 snapshot数据快照(rdb) 这是一种定时将redis内存中的数据写入磁盘文件的一种方案,这样保留这一时刻redis中的数据镜像,用于意外回滚.redis的snapshot的格 ...

  4. gridview分页

    protected void lnkbtnFrist_Click(object sender, EventArgs e) { //首页 ; this.ReadData(); } protected v ...

  5. March 29th, 2015, Thread Name is odd by increasing 1

    public class Fabric extends Thread{ public static void main(String args[]){ Thread t = new Thread(ne ...

  6. C#中正则表达式使用介绍

    摘要:本文给出了在C#下利用正则表达式实现字符串搜索功能的方法,通过对.NET框架下的正则表达式的研究及实例分析,总结了正则表达式的元字符.规则.选项等. 关键字:正则表达式.元字符.字符串.匹配 1 ...

  7. python3给图片添加水印

    #!/usr/local/bin/python3 #coding=gbk import os, io, sys, re, time, json, random from PIL import Imag ...

  8. 的二分图poj2446

    称号:id=2446">poj2446 意甲冠军:给定一个m*n矩阵,在有些地方坑,然后1*2本文叠加,反复.可以把出了坑的地方其它所有覆盖的话输出YES,否则NO 分析:有一道二分图 ...

  9. JAVA面试题解惑系列(七)——使用日期和时间

    日期和时间,不仅在考试面试题.处理的问题.似乎没有哪个项目能够避开它们.我们经常在处理用户的出生年月日.注冊日期,订单的创建时间等属性时用到,由此可见其重要性.  java.util.Date类  提 ...

  10. JS表格各行变色

    <head>    <title></title>    <script type="text/javascript">      ...