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的實質仍是擴展方法。html
擴展方法使你可以向現有類型「添加」方法,而無需建立新的派生類型、從新編譯或以其餘方式修改原始類型。 擴展方法是一種特殊的靜態方法,但能夠像擴展類型上的實例方法同樣進行調用。 ide
例如:測試
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. 若是不肯定到底使用仍是不使用擴展方法,那就不要用。this
擴展方法是C#語言的一個很好的補充,她使咱們可以編寫更好,更容易讀的代碼,可是也應該當心使用,不恰當的使用擴展方法可能致使可讀性下降,使測試困難,容易出錯。spa
System.Linq用起來那麼好,她內部是如何實現的,固然是查看源碼了。code
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中htm
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 element in source) { checked { index++; } if (predicate(element, index)) yield return element; } }
這下明白了,linq就是擴展方法,對數據進行處理,返回所須要的數據,知道了原理以後,能夠寫本身的linq擴展方法了。
我想寫一個帶有控制檯輸出的Where擴展方法blog
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 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; }
1. Linq的執行效率及優化
2. C#中linq