.NET中的泛型集合

在这里主要介绍常见的泛型集合,很多时候其并发时的线程安全性常常令我们担忧。因而简述下.NET并发时线程安全特性,其详情请见MSDN。

  • 普通集合都不支持多重并发写操作
  • 部分支持单线程写和并发读操作
  • 同时.NET4添加了大量并发集合

首先介绍常见的泛型集合接口,其大部分都位于System.Collection.Generic命名空间。

  • IEnumerable<T>,其可以获取一个IEnumerator<T>迭代器,如果从数据库的角度来看,前者是表,后者是游标,同时这两个接口是唯一具有可变性的集合接口。
  • ICollection<T>,它扩展了IEnumerable<T>,添加了Count和IsReadOnly属性,Add和Remove等操作方法,Contains等判定函数,所有的标准泛型集合都实现了该接口。
  • IList<T>,提供定位功能,包括一个索引器、Insert和RemoveAt,我们通常认为可以通过索引对该泛型集合进行随机访问。、
  • IDictionary<TKey, TValue>,表示键值对集合,扩展了ICollection<KeyValuePair<TKey, TValue>>,取值可以用TryXXX方式。
  • ISet<T>表示唯一值集,包含大量集合操作:交、并、补。

接下来介绍具体的集合泛型集合类型,在实际中需要根据具体场景选择最适合的集合类型。

  • List<T>,其是列表的默认选择,内含一个数组,并且提供列表的逻辑大小Count和后台数组的大小Capacity,当数组满了时,会进行扩容。由于是连续型的数据结构,其添加删除操作的成本较高,提供二分查找,查找效率高。同时,其Sort操作会修改原始列表的内容,与OrderBy不同,并且Sort是不稳定的,会出现相等元素顺序不同的情况。
  • 数组,最基础的集合,均派生自System.Array,包括一维数组T[10],二维数组T[10, 20]等,通过Array类的静态方法进行ConvertAll、FindAll和BinarySearch等操作。
  • Colletion<T>,位于System.Colletion.ObjectModel命名空间,为BindingList<T>和ObservableCollection<T>等扩展类型提供基类。与双向绑定相关的集合类型,注意它们只会在包装器发生变化发出通知,而基础列表改变时不会引发任何事件。
  • ReadOnlyCollection<T>和ReadOnlyObservableCollection<T>,其也类似于包装器,后者实现了INotifyCollectionChanged, INotifyPropertyChanged两个接口。
  • Dictionary<TKey, TValue>,使用散列表,查找性能的优劣取决于散列函数的优劣,默认使用Equals和GetHashCode,可以通过制定IEqualityComparer<TKey>作为参数。
  • SortList<TKey, TValue>和SortedDictionary<TKey, TValue>,两者都是字典类,前者内部维护一个排序的数组,添加删除操作的事件复杂度为O(n),后者内部维护一个红黑树,添加删除操作事件复杂度为O(log n),但会消耗更多的堆内存,使用IComparer<TKey>作比较。
  • HashSet<T>,是不含值的Dictionary<,>,具有相同性能特性,并且所维护顺序一般与添加顺序无关。
  • SortedSet<T>,是没有值得SortedDictionary<,>,维护一个红黑树,添加删除和检查操作的事件复杂度为O(log n)。提供GetViewBetween方法返回介于原始集上下限之间的另一个SortedSet<T>,注意这是一个动态的视图,会随着原始集的改变而改变。尽管看起来很方便,但需要注意的是"天下没有免费的午餐",为保持内部一致性,操作的代价更大。
  • Queue<T>,构建一个环形缓冲区,实际维护一个基础数组,包含两个索引,分别记住入队和出队的位置(Slot),如果入队指针追上出队指针,则进行扩容。提供Enqueue、Dequeue、Peek等方法进行入队、出队、查看操作。
  • Stack<T>,其实现更简单,可以看做是一个提供Push、Pop、Peek操作的List<T>。

最后介绍并行集合,也就是线程安全的集合。(注意所有的并发类型都未实现IList<T>接口)

  • IProducerConsumerCollection<T>和BlockingCollection<T>,前者是生产者/消费者模型中数据存储的抽象,后者是其包装类,使用ConcurrentQueue<T>作为后台存储,提供ToArray方法获得集合当前状态快照,TryXXX方法允许有效的失败模式减少对锁的需求。(例如,当队列中只有一个项时,两个线程同时判断它是否有项,并且都返回true,这是一个线程执行了出队操作,而另外一个线程在执行出队操作时,将抛出异常,因而需要对验证队列是否有项操作和有项就出队操作作为一个整体,需要添加锁)
  • ConcurrentBag<T>,ConcurrentQueue<T>,ConcurrentStack<T>,它们是对IProducerConsumerCollection<T>的实现,其GetEnumerator()方法返回集合快照,迭代时可以改变集合,但该改变不会反应到迭代器中。
  • ConcurrentDictionary<TKey, TValue>, 实现了IDictionary<TKey, TValue>接口。支持并发的读写和线程安全的迭代,但不同是,其在迭代过程中对字典的改变不能确定是否反应到迭代器上。

小节:在日常工作中,当遇到需要并发操作非集合类型的全局变量时,需要使用锁来处理;而当是集合类型时,就需要使用对应的并行集合类来处理,其能很好的TPL协作在一起。尤其在使用非线程安全的字典类进行并发操作时,有时会出现死循环等情形,尤其需要注意。

Tip:where T:new()

参考文献

  1. 版)[M]. 北京:人民邮电出版社, 2014. 469-483

快速入门系列--CLR--03泛型集合的更多相关文章

  1. 快速入门系列--WebAPI--04在老版本MVC4下的调整

    WebAPI是建立在MVC和WCF的基础上的,原来微软老是喜欢封装的很多,这次终于愿意将http编程模型的相关细节暴露给我们了.在之前的介绍中,基本上都基于.NET 4.5之后版本,其System.N ...

  2. 快速入门系列--MVC--01概述

    虽然使用MVC已经不少年,相关技术的学习进行了多次,但是很多技术思路的理解其实都不够深入.其实就在MVC框架中有很多设计模式和设计思路的体现,例如DependencyResolver类就包含我们常见的 ...

  3. WPF快速入门系列(4)——深入解析WPF绑定

    一.引言 WPF绑定使得原本需要多行代码实现的功能,现在只需要简单的XAML代码就可以完成之前多行后台代码实现的功能.WPF绑定可以理解为一种关系,该关系告诉WPF从一个源对象提取一些信息,并将这些信 ...

  4. WPF快速入门系列(1)——WPF布局概览

    一.引言 关于WPF早在一年前就已经看过<深入浅出WPF>这本书,当时看完之后由于没有做笔记,以至于我现在又重新捡起来并记录下学习的过程,本系列将是一个WPF快速入门系列,主要介绍WPF中 ...

  5. es6 快速入门 系列 —— 类 (class)

    其他章节请看: es6 快速入门 系列 类 类(class)是 javascript 新特性的一个重要组成部分,这一特性提供了一种更简洁的语法和更好的功能,可以让你通过一个安全.一致的方式来自定义对象 ...

  6. 快速入门系列--WebAPI--01基础

    ASP.NET MVC和WebAPI已经是.NET Web部分的主流,刚开始时两个公用同一个管道,之后为了更加的轻量化(WebAPI是对WCF Restful的轻量化),WebAPI使用了新的管道,因 ...

  7. 快速入门系列--WebAPI--03框架你值得拥有

    接下来进入的是俺在ASP.NET学习中最重要的WebAPI部分,在现在流行的互联网场景下,WebAPI可以和HTML5.单页应用程序SPA等技术和理念很好的结合在一起.所谓ASP.NET WebAPI ...

  8. 快速入门系列--MVC--02路由

    现在补上URL路由的学习,至于蒋老师自建的MVC小引擎和相关案例就放在论文提交后再实践咯.通过ASP.NET的路由系统,可以完成请求URL与物理文件的分离,其优点是:灵活性.可读性.SEO优化.接下来 ...

  9. 快速入门系列--MVC--07与HTML5移动开发的结合

    现在移动互联网的盛行,跨平台并兼容不同设备的HTML5越来越盛行,很多公司都在将自己过去的非HTML5网站应用渐进式的转化为HTML5应用,使得一套代码可以兼容不同的物理终端设备和浏览器,极大的提高了 ...

  10. Qt快速入门系列教程目录

    Qt快速入门系列教程目录

随机推荐

  1. iOS-详细解读Const

    在过去开发中,几乎每一个人都会定义宏,因为这东西实在是好用,省去了代码量而且还不容易错,而我这篇文中所介绍的const可以完美替带宏定义. 并且苹果也建议大家抛弃宏定义而转投const ,并且swif ...

  2. js多种切换图片

    分享通过js实现多种图片切换特效,这里只有手动切换哦,自动效果需自写,效果地址:http://dwz.cn/1drD5u. 下载地址:http://***/download/index/52209 适 ...

  3. DOM基础

    DOM(Document Object Model)即文档对象模型,针对HTML 和XML 文档的API(应用程序接口).DOM 描绘了一个层次化的节点树,运行开发人员添加.移除和修改页面的某一部分. ...

  4. IOS的一些小技巧

    1.播放短声音 SystemSoundID shake_sound_male_id = ; NSString *thesoundFilePath = [[NSBundle mainBundle] pa ...

  5. 视频文件写入转换之图像处理-OpenCV应用学习笔记五

    在<笔记二>中我们做了视频播放和控制的实现,仅仅算是完成了对视频文件的读取操作:今天我们来一起练习下对视频文件的写入操作:格式转换. 实现功能: 打开一个视频文件play.avi,读取文件 ...

  6. Hibernate component mapping

    A Component is a containted object that is be persisted value type and not an entity.But you can emb ...

  7. 多个div居中显示

    页面中有多个div时我们希望并排居中显示,可以通过在并排显示的div上一层再加一个div,设定宽度,然后让其居中显示达到需要的效果. 关键是要对外层div设定宽度. <!DOCTYPE html ...

  8. linux-10 基本命令之查看内存使用情况- free,history,who,last

    free 命令 显示当前系统中内存的使用量情况  格式如下:free[-m/-g] 以m为单位显示当前内存的使用情况 [root@localhost /]# free -m 内存总量 已用量 可用量 ...

  9. MongoDB与内存

    来自  http://www.ttlsa.com/mongodb/mongodb-and-memory/# 但凡初次接触MongoDB的人,无不惊讶于它对内存的贪得无厌,至于个中缘由,我先讲讲Linu ...

  10. 七牛php sdk 生成上传凭证时出现 undefined function Qiniu_SetKeys()

    将qiniu/http.php文件改名即可,原因是xampp等集成环境会安装pear存在了http.php