如何在淘宝开网站建设,免费推广软件流量精灵,wordpress怎么采集,朋友圈广告一#xff1a;背景1. 讲故事前段时间将公司的一个项目从 4.5 升级到了 framework 4.8 #xff0c;编码的时候发现 Enumerable 中多了三个扩展方法#xff1a; Append, Prepend, ToHashSet#xff0c;想必玩过jquery的朋友一眼就能看出这三个方法的用途#xff0c;这篇就和… 一背景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 IEnumerableTSource AppendTSource(this IEnumerableTSource source, TSource element)
{if (source null){throw Error.ArgumentNull(source);}AppendPrependIteratorTSource appendPrependIterator source as AppendPrependIteratorTSource;if (appendPrependIterator ! null){return appendPrependIterator.Append(element);}return new AppendPrepend1IteratorTSource(source, element, appending: true);
}private class AppendPrepend1IteratorTSource : AppendPrependIteratorTSource
{public AppendPrepend1Iterator(IEnumerableTSource 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;}}
从上面的源码来看这玩意做的还是挺复杂的继承关系依次是 AppendPrepend1IteratorTSource - AppendPrependIteratorTSource - IteratorTSource 这里大家要着重看一下 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 };IEnumerableint collection arr;foreach (var item in arr2){collection collection.Append(item);}foreach (var item in collection){Console.WriteLine(item);}}
结果也是非常简单的因为 IEnumerable 是非破坏性的操作所以你需要在 Append 之后用类型给接住接下来找一下底层源码。
public static IEnumerableTSource AppendTSource(this IEnumerableTSource source, TSource element)
{if (source null){throw Error.ArgumentNull(source);}AppendPrependIteratorTSource appendPrependIterator source as AppendPrependIteratorTSource;if (appendPrependIterator ! null){return appendPrependIterator.Append(element);}return new AppendPrepend1IteratorTSource(source, element, appending: true);
}private class AppendPrepend1IteratorTSource : AppendPrependIteratorTSource
{public override AppendPrependIteratorTSource Append(TSource item){if (_appending){return new AppendPrependNTSource(_source, null, new SingleLinkedNodeTSource(_item).Add(item), 0, 2);}return new AppendPrependNTSource(_source, new SingleLinkedNodeTSource(_item), new SingleLinkedNodeTSource(item), 1, 1);}
}private class AppendPrependNTSource : AppendPrependIteratorTSource
{public override AppendPrependIteratorTSource Append(TSource item){SingleLinkedNodeTSource appended (_appended ! null) ? _appended.Add(item) : new SingleLinkedNodeTSource(item);return new AppendPrependNTSource(_source, _prepended, appended, _prependCount, _appendCount 1);}
}
从上面的代码可以看出当你 Append 多次的时候本质上就是多次调用 AppendPrependNTSource.Append() 而且在调用的过程中一直将你后续添加的元素追加到 SingleLinkedNode 单链表中这里要注意的是 Add 采用的是 头插法所以最后插入的元素会在队列头部如下图如果你不信的话我可以在 vs 调试中给您展示出来。貌似说的有点啰嗦最后大家观察一下 AppendPrependNTSource.MoveNext 的实现就可以了。说了这么多我想你应该明白了哈。2. Prepend本质上来说 Prepend 和 Append 是一对的一个是在前面插入一个是在后面插入不要想歪了如果你细心的话你会发现 Prepend 也是用了这三个类 AppendPrepend1IteratorTSourceAppendPrependIteratorTSourceAppendPrependNTSource 以及 单链表 SingleLinkedNodeTSource这个就留给大家自己研究了哈。3. ToHashSet我以前在全内存开发中会频繁的用到 HashSet毕竟它的时间复杂度是 O(1) 而且在 Enumerable 中早就有了 ToList 和 ToDictionary凭啥没有 ToHashSet在以前只能将 source 塞到 HashSet 的构造函数中如 new HashSetint(source) 想想也是够奇葩的哈而且我还想吐糟一下的是居然到现在还没有 AddRange 批量添加方法气人哈接下来用 ILSpy 看一下这个扩展方法是如何实现的。三总结总体来说这三个方法还是很实用的我相信在后续的版本中 Enumerable 下的扩展方法还会越来越多越来越人性化人生苦短 我用C#。