.NET中扩展方法和Enumerable(System.Linq)
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)的更多相关文章
- 扩展方法和Enumerable
.NET中扩展方法和Enumerable(System.Linq) LINQ是我最喜欢的功能之一,程序中到处是data.Where(x=x>5).Select(x)等等的代码,她使代码看起来更好 ...
- 【转载】.NET(C#): Task.Unwrap扩展方法和async Lambda
.NET(C#): Task.Unwrap扩展方法和async Lambda 目录 Task.Unwrap基本使用 Task.Factory.StartNew和Task.Run的Unwrap操作 使用 ...
- 线程中sleep方法和wait方法有什么区别?(转)
本文转自https://www.cnblogs.com/linkstar/p/6043846.html 线程中sleep方法和wait方法有什么区别? 如果你没有接触过java的多线程,那么多对于 ...
- Classloader中loadClass()方法和Class.forName()区别
Classloader中loadClass()方法和Class.forName()都能得到一个class对象,那这两者得到的class对象有什么区别呢 1.java类装载的过程 Java类装载有三个步 ...
- Hibernate中evict方法和clear方法说明
Hibernate中evict方法和clear方法说明 先创建一个对象,然后调用session.save方法,然后调用evict方法把该对象清除出缓存,最后提交事务.结果报错: Exception i ...
- ThinkPHP 中M方法和D方法详解----转载
转载的地址,http://blog.163.com/litianyichuanqi@126/blog/static/115979441201223043452383/ 自己学到这里的时候,不能清除的分 ...
- ThinkPHP 中M方法和D方法的具体区别(转)
M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...
- ThinkPHP 中M方法和D方法的具体区别
M方法和D方法的区别 ThinkPHP 中M方法和D方法都用于实例化一个模型类,M方法 用于高效实例化一个基础模型类,而 D方法 用于实例化一个用户定义模型类. 使用M方法 如果是如下情况,请考虑使用 ...
- jquery中prop()方法和attr()方法
接着上一篇笔记的疑惑,找了下prop()方法和attr()方法的区别. 原来query1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. ...
随机推荐
- HSSFWorkBooK用法 ---Excel表的导出和设置
public ActionResult excelPrint() { HSSFWorkbook workbook = new HSSFWorkbook();// 创建一个Excel文件 HSSFShe ...
- PAT 1011-1020 题解
早期部分代码用 Java 实现.由于 PAT 虽然支持各种语言,但只有 C/C++标程来限定时间,许多题目用 Java 读入数据就已经超时,后来转投 C/C++.浏览全部代码:请戳 本文谨代表个人思路 ...
- python 读写XLS
需要库: xlrd, xlwt, xlutils 导入 import xlrd from xlutils.copy import copy 打开文件 data = xlrd.open_workbook ...
- WPF 使用 SharpDX
原文:WPF 使用 SharpDX 版权声明:博客已迁移到 http://lindexi.gitee.io 欢迎访问.如果当前博客图片看不到,请到 http://lindexi.gitee.io 访问 ...
- python 两个链表的第一个公共结点
题目描述 输入两个链表,找出它们的第一个公共结点. 看到这道题的时候,很多人的第一反应就是采用蛮力的方法:在第一个链表上顺序遍历每个节点,每遍历到一个节点的时候,在第二个链表上顺序遍历每个节点.如 ...
- 2 WCF里面配置的含义
1 首先介绍所谓的a,b,c. a就是address 地址: b binding 绑定的协议 譬如http tcp udp 利用这些协议方式请求address: c contract 代表请求的规 ...
- qt4.8.7 源码在win7+vs2010环境的x64编译(qt 64位)
由于qt官网上,没有直接提供x64的安装包,但由于项目需要x64的qt,所以,小编不得不下载qt的源码,经历了一次长达约4个小时的编译过程.今年国庆7天,就遭这事上了,哈哈~~~ 几个下载链接: qt ...
- 关于idea maven工程创建struts2入门配置及案例
1.在maven工程下添加需要导入的jar包节点 <dependencies> <dependency> <groupId>org.apache.struts< ...
- Binding控件某个属性
<Grid Margin="60"> <Grid.RowDefinitions> <RowDefinition Height="*" ...
- ASP .NET Controller返回类型
返回类型 return View(model); 即返回htmlreturn Json("String"); 返回Json格式的数据return File(new byte[] { ...