日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Enumerable 下又有新的扩展方法啦,快来一睹为快吧

發布時間:2023/12/4 编程问答 39 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Enumerable 下又有新的扩展方法啦,快来一睹为快吧 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一:背景

1. 講故事

前段時間將公司的一個項目從 4.5 升級到了 framework 4.8 ,編碼的時候發現 Enumerable 中多了三個擴展方法:?Append, Prepend, ToHashSet,想必玩過jquery的朋友一眼就能看出這三個方法的用途,這篇就和大家一起來聊聊這三個方法的底層源碼實現,看有沒有什么新東西可以挖出來。

二:Enumerable 下的新擴展方法

1. Append

看到這個我的第一印象就是?Add?方法, 可惜在 Enumerable 中并沒有類似的方法,可能后來程序員在這塊的呼聲越來越高,C#開發團隊就彌補了這個遺憾。

<1> 單條數據的追加

接下來我寫一個小例子往集合的尾部追加一條數據,如下代碼所示:

static void Main(string[] args){var arr = new int[2] { 1, 2 };var result = Enumerable.Append(arr, 3);foreach (var item in result){Console.WriteLine(item);}}

邏輯還是非常清晰的,再來看看底層源碼是怎么實現的。

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element) {if (source == null){throw Error.ArgumentNull("source");}AppendPrependIterator<TSource> appendPrependIterator = source as AppendPrependIterator<TSource>;if (appendPrependIterator != null){return appendPrependIterator.Append(element);}return new AppendPrepend1Iterator<TSource>(source, element, appending: true); }private class AppendPrepend1Iterator<TSource> : AppendPrependIterator<TSource> {public AppendPrepend1Iterator(IEnumerable<TSource> source, TSource item, bool appending) : base(source){_item = item;_appending = appending;}public override bool MoveNext(){switch (state){case 1:state = 2;if (!_appending){current = _item;return true;}goto case 2;case 2:GetSourceEnumerator();state = 3;goto case 3;case 3:if (LoadFromEnumerator()){return true;}if (_appending){current = _item;return true;}break;}Dispose();return false;}}

從上面的源碼來看,這玩意做的還是挺復雜的,繼承關系依次是:?AppendPrepend1Iterator<TSource> -> AppendPrependIterator<TSource> -> Iterator<TSource>, 這里大家要著重看一下?MoveNext()?里面的兩個方法 GetSourceEnumerator() 和 LoadFromEnumerator(),如下代碼所示:

可以看到,第一個方法用于獲取 Array 這個數據源,下面這個方法用于遍歷這個 Array,當 foreach 遍歷完之后,執行 case 3 語句,也就是下面的 if 語句,將你追加的 3 迭代一下,如下圖:

<2> 批量數據的追加

我們知道集合的添加除了 Add 還有 AddRange,很遺憾,Enumerable下并沒有找到類似的 AppendRange 方法,那如果要實現 AppendRange 操作該怎么處理呢?哈哈,只能自己 foreach 迭代啦,如下代碼:

static void Main(string[] args){var arr = new int[2] { 1, 2 };var arr2 = new int[3] { 3, 4, 5 };IEnumerable<int> collection = arr;foreach (var item in arr2){collection = collection.Append(item);}foreach (var item in collection){Console.WriteLine(item);}}

結果也是非常簡單的,因為 IEnumerable 是非破壞性的操作,所以你需要在 Append 之后用類型給接住,接下來找一下底層源碼。

public static IEnumerable<TSource> Append<TSource>(this IEnumerable<TSource> source, TSource element) {if (source == null){throw Error.ArgumentNull("source");}AppendPrependIterator<TSource> appendPrependIterator = source as AppendPrependIterator<TSource>;if (appendPrependIterator != null){return appendPrependIterator.Append(element);}return new AppendPrepend1Iterator<TSource>(source, element, appending: true); }private class AppendPrepend1Iterator<TSource> : AppendPrependIterator<TSource> {public override AppendPrependIterator<TSource> Append(TSource item){if (_appending){return new AppendPrependN<TSource>(_source, null, new SingleLinkedNode<TSource>(_item).Add(item), 0, 2);}return new AppendPrependN<TSource>(_source, new SingleLinkedNode<TSource>(_item), new SingleLinkedNode<TSource>(item), 1, 1);} }private class AppendPrependN<TSource> : AppendPrependIterator<TSource> {public override AppendPrependIterator<TSource> Append(TSource item){SingleLinkedNode<TSource> appended = (_appended != null) ? _appended.Add(item) : new SingleLinkedNode<TSource>(item);return new AppendPrependN<TSource>(_source, _prepended, appended, _prependCount, _appendCount + 1);} }

從上面的代碼可以看出,當你 Append 多次的時候,本質上就是多次調用?AppendPrependN<TSource>.Append()?,而且在調用的過程中,一直將你后續添加的元素追加到?SingleLinkedNode?單鏈表中,這里要注意的是 Add 采用的是 頭插法,所以最后插入的元素會在隊列頭部,如下圖:

如果你不信的話,我可以在 vs 調試中給您展示出來。

貌似說的有點啰嗦,最后大家觀察一下?AppendPrependN<TSource>.MoveNext?的實現就可以了。

說了這么多,我想你應該明白了哈。

2. Prepend

本質上來說 Prepend 和 Append 是一對的,一個是在前面插入,一個是在后面插入,不要想歪了,如果你細心的話,你會發現 Prepend 也是用了這三個類:?AppendPrepend1Iterator<TSource>,AppendPrependIterator<TSource>,AppendPrependN<TSource>?以及 單鏈表?SingleLinkedNode<TSource>,這個就留給大家自己研究了哈。

3. ToHashSet

我以前在全內存開發中會頻繁的用到 HashSet,畢竟它的時間復雜度是?O(1)?,而且在 Enumerable 中早就有了 ToList 和 ToDictionary,憑啥沒有 ToHashSet,在以前只能將 source 塞到 HashSet 的構造函數中,如:?new HashSet<int>(source)?,想想也是夠奇葩的哈,而且我還想吐糟一下的是居然到現在還沒有 AddRange 批量添加方法,氣人哈,接下來用 ILSpy 看一下這個擴展方法是如何實現的。

三:總結

總體來說這三個方法還是很實用的,我相信在后續的版本中 Enumerable 下的擴展方法還會越來越多,越來越人性化,人生苦短, 我用C#。

總結

以上是生活随笔為你收集整理的Enumerable 下又有新的扩展方法啦,快来一睹为快吧的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。