C# 《编写高质量代码改善建议》整理&笔记 --(二)集合
题记:这篇,主要就是讲述集合之类。好好总结一番。
1.多数情况下使用foreach进行循环遍历
先假设一下如果对集合进行遍历,假设存在一个数组,其遍历模式可能采用依据索引来进行遍历的方法;又假设存在一个HashTable,其
遍历模式可能按照键值来进行遍历。无论是哪个集合,他们的遍历没有一个公共的接口,那么客户端在调用的时候,相当于对具体类型进行了
编码,这样一来,当需求发生变化时,就必须修改我们的代码。并且由于客户端代码过多的关注了集合内部的实现,代码的移值性就会变得很差,这直接违反了面向对象中的开闭原则,于是迭代器模式就诞生了。
(简而言之,就是在不管集合内部如何实现的情况下,完成遍历)
foreach 优势:语法简明,自动将代码置入try-finally,实现了IDispose接口,他会在循环结束后调用Dispose方法。
2.foreach 不能代替for
foreach不支持循环时对集合进行增删操作。如果在foreach中增/删某一元素,则会抛出异常。
原因:foreach循环使用了迭代器进行集合的遍历,它在FCL提供的迭代器内部维护了一个对集合版本的控制。
集合版本:简单来说就是一个整型变量,任何对集合的增删操作都会使版本号+1。
foreach循环会调用MoveNext方法来便利元素,MoveNext方法内部会进行版本号的检测,一旦版本号变动,
就会抛异常。
for循环在实现上所有不同。(使用索引器,不会对版本号判断)循环中增删元素不会抛异常。
由于for循环和foreach循环在实现上有所不同(前者是索引器,后者是迭代器),因此两者在性能上的争议
没有停止过。但是双方都承认在时间和内存上存在损耗。
3.选择正确的集合。
从图中可以看出集合总体分为线性集合和非线性集合。
线性集合:指元素具有唯一的前驱和后驱的数据结构类型;
非线性集合指具有多个前驱和后驱的数据结构类型。
(非线性集合用的比较少,而且还很难,这边就不讲述)
如果集合的数目固定并且不涉及转型,使用数组效率高,否则使用List<T>
线性集合按存储方式又分为直接存储和顺序存储。
直接存储
是指该类型的集合数据元素可以直接通过下标(index)来访问,如Array(List,数组),string,struct
优点:向数据结构中添加元素是很搞笑的,直接放在数据末尾的第一个空位就可以。
缺点:向集合插入元素将会变得低效,他需要给插入的元素腾出位置并顺序移动后面的元素。
顺序存储
即线性表。可以动态的扩大和缩小,他在一片连续的区域中存储数据元素。线性表不能按照索引进行查找,
它是通过对地址的引用来搜索元素的,为了找到某个元素,他必须遍历所有元素,直到找到对应的元素为止。
优点:插入,删除效率高。
缺点:查找的效率相对低一些。
a.队列Queue,先进先出。
b.栈Stack,先进后出。
c.字典Dictionary,键值对。
d.双向链表 LinkedList<T>, 是一个类型为LinkedListNode的元素对象的集合、当我们需要在集合中插入,删除要求
快的时候,可以使用。
4.确保集合的线程安全
foreach循环不能代替for新欢一个重要原因居室在迭代过程中第集合本身进行了增删操作。将此场景
移值到多线程场景中:确保集合的线程安全:集合线程安全是指在多个线程中添加或删除元素时,线程之间
必须保持同步。
5.理解延迟求值和主动求值
在延迟执行求值的情况,只是定义了一个查询,而不是立刻执行。对查询结果的访问每次都hi遍历原集合。对
调用ToList,ToArray等方法,将会使其立刻执行。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 分享 3 个 .NET 开源的文件压缩处理库,助力快速实现文件压缩解压功能!
· Ollama——大语言模型本地部署的极速利器
· DeepSeek如何颠覆传统软件测试?测试工程师会被淘汰吗?