.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(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. ...
随机推荐
- 安卓手机可以连上wifi但无法上网的解决办法
作者:朱金灿 来源:http://blog.csdn.net/clever101 前晚我的安卓手机还可以连接wifi上网,昨晚显示已经连接,但是死活打不开网页.于是到网上查了下,发现要将原来的DHCP ...
- ListView 泛利
0ListView基本属性 1介绍 Listview节约内存的几种写法 2技巧一:解决ListView的ItemView中带有Button时,OnItemClick无效的问题 3技巧二Listvie ...
- 使用Toast进行用户提醒(转)
Toast是Android提供的一个轻量级的用户提醒控件,使用也很简单,就相当一个极简的dialog!!!下面将向您介绍一些Toast的详细用法: 1.普遍使用的方法: Context context ...
- 【转】mybatis 一对一与一对多collection和association的使用
转自:https://www.cnblogs.com/yansum/p/5819973.html (有修改和补充,红色字体部分) 在mybatis如何进行一对一.一对多的多表查询呢?这里用一个简单 ...
- 中英文对照 —— 手机 App/PC 端软件(系统)、互联网
0. 经典 & 缩略词 SMS:short message service,短信息服务, SMS code,短信验证码: swipe:vt. 猛击:偷窃:刷-卡 Swipe up/down/r ...
- IME输入法编程心得
原文:IME输入法编程心得 posted @ 2012-11-30 00:42 from [FreedomShe] 自然语言处理的输入法作业成品没有做出来,但不想再在蛋疼的Win32上面耗费时间了,整 ...
- 文件上传(bootstrap fileinput)
在做Excel文件上传和下载时,原生文件输入框太不美观,从网上找的bootstrap fileinput还是挺漂亮的, 需要引用的文件 //4.fileUpload bundles.Add(new S ...
- WinForm和WPF颜色对象的转换
原文:WinForm和WPF颜色对象的转换 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/huangli321456/article/details ...
- android自定义View绘制天气温度曲线
原文:android自定义View绘制天气温度曲线 版权声明:本文为博主原创文章,未经博主允许不得转载. https://blog.csdn.net/u012942410/article/detail ...
- WPF实现选项卡效果(3)——自定义动态添加的AvalonDock选项卡内容
原文:WPF实现选项卡效果(3)--自定义动态添加的AvalonDock选项卡内容 简介 在前面一篇文章里面,我们实现了AvalonDock选项卡的动态添加,但是对于选项卡里面的内容,我们并没有实现任 ...