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 == 1) { 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 = -1; foreach (TSource
elementin 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 = 0; 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() - 1; for (int i
= length; i >0; i--) { int j = rd.Next(i + 1); 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
itemin 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的执行效率及优化 <https://www.cnblogs.com/zhao123/p/9687799.html>

2. C#中linq <https://www.cnblogs.com/zhao123/p/3926025.html>

友情链接
KaDraw流程图
API参考文档
OK工具箱
云服务器优惠
阿里云优惠券
腾讯云优惠券
华为云优惠券
站点信息
问题反馈
邮箱:[email protected]
QQ群:637538335
关注微信