关于.NET的集合总结

集合是一些有共同特征的独立数据项组成的,通过集合,我们可以可以使用相同的调用代码来处理一个集合的所有元素,而不用单独处理每一个单独的项。.net的集合诸如(System.Array类以及 System.Collections命名空间)数组、列表、队列、堆栈、哈希表、字典甚至(System.Data下)DataSet、DataTable,还有2.0中加入的集合的泛型版本(System.Collections.Generic和 System.Collections.ObjectModel),4.0中引入的有效线程安全操作的集合(System.Collections.Concurrent)。

面对这么多的集合,你了解各个集合有哪些优势,在一个特定的场景中使用哪个集合吗?本文试图探讨一下这个问题,泛泛而谈,不涉及深入的内存数据结构的追究,希望能给大家带来一些益处。

集合接口
        在分别讨论各种集合之前,我们先讨论一下集合的共性,整个集合体系的继承层次。

ICollection 接口是 System.Collections 命名空间中类的基接口,而相应的ICollection<T>是所有泛型版本集合的基接口。所有的的集合类都直接或间接的继承他们。

ICollection又继承IEnumerable,来提供方便的枚举功能,不过更值得注意ICollection提供同步访问的线程安全性控制:

IsSynchronized:获取一个值,该值指示是否同步对 ICollection 的访问(线程安全)。

SyncRoot:获取可用于同步对 ICollection 的访问的对象。

例如,我们可以通过以下来对集合进行线程安全访问,不过有些集合提供Synchronized方法来提供线程安全集合的封装。


代码如下:

ICollection myCollection = someCollection;
lock(myCollection.SyncRoot)
{
       // Insert your code here.
}

不过默认情况下集合不是线程安全的。如果需要对集合进行可伸缩的且高效的多线程访问,请使用System.Collections.Concurrent命名空间中的某个类。

而与非泛型版本不同的是,泛型版本的集合除了实现了泛型的接口外,也实现了非泛型的相应的接口。如ICollection<T>实现了IEnumerable和IEnumerable<T>,但是泛型集合却没有提供同步访问的线程安全控制,也就是说泛型集合的同步访问,我们必须自己去处理同步或使用System.Collections.Concurrent命名空间中的某个类。

另外,IList和IDictionary分别继承自ICollection,IList的实现者(如Array、ArrayList 或 List<T>等)和ICollection的实现者(例如 Queue、ConcurrentQueue<T>、Stack、 ConcurrentStack<T>或 LinkedList<T>)的每个元素都是一个值,而IDictionary的实现者(例如 Hashtable 和 SortedList 类、Dictionary<TKey, TValue> 和 SortedList<TKey, TValue> 泛型类)每个元素都是一个键值对。

接下来,我们将分别讨论和比较下一些常用的集合。

数组Array
        Array不是System.Collections的一部分,但是它继承自IList接口。.net的Array可以有多维数组、交错数组,甚至创建下限不是0是数组,默认情况下推荐使用下限是0的一维数组,这常用的数组是经过优化的,性能最高。

与System.Collections集合不同的是,Array具有固定的容量,若要增加容量,您必须创建具有所需容量的新 Array 对象,将旧 Array 对象中的元素复制到新对象中,然后删除该旧 Array。而System.Collections下的集合在达到当前容量时可自动扩充容量:内存被重新分配,元素从旧集合复制到新集合中。 这减少了使用集合所需的代码,但是,集合的性能可能仍受到消极影响。 因此我们应将初始容量设置为集合的估计的大小以避免因多次重新分配导致的不佳性能。

System.Collections下的集合类
        该类型的集合都具有排序功能且大多数经过了索引。能自动处理内存管理,容量按需扩大。

ArrayList和List<T>:List<T>是ArrayList的泛型版本,它们和Array一样都是基于索引访问,每个数据项只保存一个数据值,但是它们提供比Array更强大的功能和操作,使得它们也更容易使用。性能方面,泛型版本总是比非泛型更优先采用,除非成员类型是object类型,因为泛型版本免除了装箱和拆箱的操作;在不需要重新分配集合容量的情况下,List<T>的性能与同类型的数组十分相近。另外,ArrayList可以很方便的创建同步版本,但Array和List<T>的同步工作必须有自己完成。

Hashtable 和 Dictionary 集合类型:这些集合每个项是一个键值对。Dictionary<Tkey,Tvalue>是Hashtable的泛型版本。Hashtable对象是由包含集合元素的存储桶组成的,每个存储桶与使用元素键基于哈希函数生成的一个哈希码关联,包含多个元素。因此这类集合比其它的大多数集合在搜索和检索数据上更快捷。而同样的Dictionary<Tkey,Tvalue>总是比Hashtable性能更好,因此推荐使用,多线程同步使用ConcurrentDictionary<TKey, TValue>类。

已排序的集合类型:System.Collections.SortedList 类、System.Collections.Generic.SortedList<TKey, TValue> 泛型类和System.Collections.Generic.SortedDictionary<TKey, TValue> 泛型类,它们都实现 IDictionary 接口,两个泛型类还实现了System.Collections.Generic.IDictionary<TKey, TValue>,与Hashtable类似每个元素都是一个键值对,但是它们以基于键的排序顺序维护元素,并没有哈希表的 O(1) 插入和检索特性。非泛型的枚举项是DictionaryEntry 对象,而两个泛型类型返回 KeyValuePair<TKey, TValue> 对象。它们最重要的重点是它们是按照System.Collections.IComparer实现或System.Collections.Generic.IComparer<T>的实现排好序的。SortedList允许我们通过索引和键访问,而SortedDictionary只能通过键访问,SortedList还更省内存。

队列和堆栈:就不多做介绍了,如果要临时存储数据,数据只在访问一次后就放弃,就可以使用这类集合。队列和堆栈的差别就在于访问的先后不一样,相信大家都很清楚了。他们也分别有各自的泛型版本和线程安全版本:System.Collections.Queue 类、System.Collections.Generic.Queue<T> 类和System.Collections.Concurrent.ConcurrentQueue<T>,System.Collections.Stack类以及 System.Collections.Generic.Stack<T> 和System.Collections.Concurrent.ConcurrentStack<T>。

Set集合:该类型集合的两个类型HashSet<T> 和 SortedSet<T>,都实现了ISet<T>接口。Set集合最接近于数学中的集合,专门用于实现了数学的Set操作,如并集、交集等运算。其中Hashset<T>没有排序,不能有重复元素,可以视为Dictionary<TKey,TValue>的不包含值的版本,基于哈希键提供高性能的Set运算。而SortedSet<T>提供排好序的Set操作的集合。这里要提的是有些集合也提供了Set运算的扩展方法和LINQ也提供的Set运算,不过它们都返回新 的IEnumerable<T>集合,而Set集合的Set操作都是修改当前集合,并且提供一个更大、更可靠的运算集合。

这并不是.net集合的全部,它还有位集合和专用集合。

位集合
        它的每个元素是一个标识位,而不是对象。其中有BitVector32和BitArray。

BitVector32是一个结构,只能存储32位数据,可用来存储位标识或小整数,它是值类型,因此性能更好。

而BitArray是引用类型,它的容量始终与计数相同,可以通过Length属性来分配或删除元素。

专用集合
        NameValueCollection 基于 NameObjectCollectionBase;但NameValueCollection 接受一键多值,而 NameObjectCollectionBase 只接受一键一值。

System.Collections.Specialized 命名空间中的一些强类型集合包括 StringCollection 和 StringDictionary,它们都包含完全是字符串的值集合和字典。

CollectionsUtil 类提供一系列静态方法可以用来创建不区分大小写的Hashtable或SortedList集合的实例。

有些集合可以转换。例如,HybridDictionary 类起初是 ListDictionary,增大后就变为 Hashtable。

另外,KeyedCollection<TKey, TItem> 是介于列表和字典之间的混合类型,它提供了一种存储包含自己键的对象的方法,当元素数目达到指定阈值时,它也可以创建查找字典。

ListDictionary:使用单向链接列表实现 IDictionary。建议为通常包括少于 10 个项目的集合,当数据项较少时,提供比Hashtable更好的性能。

LINQ to Objects
         我们可以使用 LINQ 查询来访问内存中的实现了System.Collections.IEnumerable 或 System.Collections.Generic.IEnumerable<T> 接口对象。

它提供了一种通用的数据访问模式;与标准 foreach 循环相比,它通常更加简洁,可读性更高;提供了强大的筛选、排序和分组功能。

如何抉择
        我们首先要明确,如果存在泛型版本,优先使用。

选择之前请先确定几个问题:
是否需要按序列访问,元素在访问后放弃?

访问的顺序是先进先出或后进先出、随机访问?

是基于索引的访问,还是基于键的访问?

是只有值,还是键值对形式?

是一对一,还是一对多?

是否允许重复?

是按进入的顺序保存,还是需要按一定的规则排好序的,还是无所谓?

是否需要更快速度的检索和访问?

(0)

相关推荐

  • VBA UsedObjects 集合用法

    返回一个 UsedObjects 集合后,便可用 Count 属性来确定 Microsoft Excel 应用程序中所用对象的个数. 在本示例中,Microsoft Excel 确定已分配的对象的个数,并通知用户.本示例假定在应用程序中执行重新计算,并且在完成前中断重新计算. 复制代码 代码如下: Sub CountUsedObjects() MsgBox "The number of used objects in this application is: " & _ App

  • UserAccessList 集合的功能(VBA)

    返回一个 UserAccessList 集合后,便可用 Count 属性来确定访问受保护区域的用户数量.在下例中,Microsoft Excel 将访问第一个受保护区域的用户的数量通知给用户.本示例假定受保护的区域位于活动工作表上. 复制代码 代码如下: Sub UseDeleteAll() Dim wksSheet As Worksheet Set wksSheet = Application.ActiveSheet ' Notify the user the number of users

  • 详解Backbone.js框架中的模型Model与其集合collection

    什么是 Model Backbone 的作者是这样定义 Model 的: Model 是任何一个 web 应用的核心,它包含了交互的数据以及大部分的逻辑.例如:转化.验证.属性和访问权限等. 那么,我们首先来创建一个Model: Person = Backbone.Model.extend({ initialize: function(){ alert("Welcome to Backbone!"); } }); var person = new Person; 上述代码中,我们定义了

  • Backbone.js中的集合详解

    Backbone.js的集合只是一个简单的有序集的模型.通过适应模型和集合,我们可以避免数据处理逻辑放到了我们的视图层.此外,模型和集合还提供了便利的与后端一起工作的方法,当数据发生变化时,可以自动化地标记Backbone.js视图.这样,它可以用于如下的情况: 复制代码 代码如下: Model: Animal, Collection: Zoo 通常情况下你的集合只适应一种模型,但模型本身并不局限于集合的类型. 复制代码 代码如下: Model: person, Collection: Offi

  • Go语言使用sort包对任意类型元素的集合进行排序的方法

    本文实例讲述了Go语言使用sort包对任意类型元素的集合进行排序的方法.分享给大家供大家参考.具体如下: 使用sort包的函数进行排序时,集合需要实现sort.Inteface接口,该接口中有三个方法: 复制代码 代码如下: // Len is the number of elements in the collection.  Len() int  // Less reports whether the element with  // index i should sort before t

  • PHP 如何获取二维数组中某个key的集合

    本文为代码分享,也是在工作中看到一些"大牛"的代码,做做分享. 具体是这样的,如下一个二维数组,是从库中读取出来的. 代码清单: 复制代码 代码如下: $user = array( 0 => array( 'id' => 1, 'name' => '张三', 'email' => 'zhangsan@sina.com', ), 1 => array( 'id' => 2, 'name' => '李四', 'email' => 'lisi@

  • 基于MVC5和Bootstrap的jQuery TreeView树形控件(二)之数据支持json字符串、list集合

    在上篇给大家介绍了基于MVC5和Bootstrap的jQuery TreeView树形控件(一)之数据支持json字符串.list集合. 这种方式其实还是利用list集合的方式传给前台,只不过在前台做了一些小小的变化,而控制器代码也进行了部分的优化,值的一提的是:没用的ajax前后台交互舍弃掉了. 控制器代码如下: //实例化公共静态字典表集合 public static List<TC_DictionaryInfo> DInfo = new List<TC_DictionaryInfo

  • 基于MVC5和Bootstrap的jQuery TreeView树形控件(一)之数据支持json字符串、list集合

    本文支持两种方式的数据,一种为List集合,一种为json字符串. 先来介绍一下后台返回list集合(推荐使用此方法): 控制器代码如下: public static List<TC_DictionaryInfo> DInfo = new List<TC_DictionaryInfo>(); /// <summary> /// TreeView视图 /// </summary> /// <returns></returns> publ

  • Go语言之自定义集合Set

    一.Go语言实战--自定义集合Set 在Go语言中有作为Hash Table实现的字典(Map)类型,但标准数据类型中并没有集合(Set)这种数据类型.比较 Set 和 Map 的主要特性,有类似特性如下: 它们中的元素都是不可重复的. 它们都只能用迭代的方式取出其中的所有元素. 对它们中的元素进行迭代的顺序都是与元素插入顺序无关的,同时也不保证任何有序性. 但是,它们之间也有一些区别,如下: Set 的元素是一个单一的值,而 Map 的元素则是一个键值对. Set 的元素不可重复指的是不能存在

  • C#写入对象或集合类型数据到xml文件的方法

    本文实例讲述了C#写入对象或集合类型数据到xml文件的方法.分享给大家供大家参考.具体实现方法如下: public static string SerializeToXmlString(object objectToSerialize) { MemoryStream memoryStream = new MemoryStream(); System.Xml.Serialization.XmlSerializer xmlSerializer = new System.Xml.Serializati

随机推荐