`
pcajax
  • 浏览: 2106831 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

C#笔记7:集合类

阅读更多

C#笔记7:集合类

本章概要:

1:为什么要使用泛型集合

2:集合的线程安全

    2.1:Syncronized静态方法和SyncRoot实例属性的用法

3:选择集合类

4:位集合

 

1:为什么要使用泛型集合

     针对 .NET Framework 的 2.0 版和更高版本的应用程序应当使用 System.Collections.Generic 命名空间中的泛型集合类,与对应的非泛型类相比,这些类提供了更高的类型安全性和效率。为什么这么说呢,看下面的例子:

// The .NET Framework 1.1 way to create a list:
System.Collections.ArrayList list1 = new System.Collections.ArrayList();
list1.Add(3);
list1.Add(105);

System.Collections.ArrayList list2 = new System.Collections.ArrayList();
list2.Add("It is raining in Redmond.");
list2.Add("It is snowing in the mountains.");

 

 

     添加到 ArrayList 中的任何引用或值类型都将隐式地向上强制转换为 Object。 如果项是值类型,则必须在将其添加到列表中时进行装箱操作,在检索时进行取消装箱操作。 强制转换以及装箱和取消装箱操作都会降低性能;在必须对大型集合进行循环访问的情况下,装箱和取消装箱的影响非常明显。

     另一个限制是缺少编译时类型检查;因为 ArrayList 会将所有项都强制转换为 Object,所以在编译时无法防止客户端代码执行类似如下的操作:

System.Collections.ArrayList list = new System.Collections.ArrayList();
// Add an integer to the list.
list.Add(3);
// Add a string to the list. This will compile, but may cause an error later.
list.Add("It is raining in Redmond.");

int t = 0;
// This causes an InvalidCastException to be returned.
foreach (int x in list)
{
    t += x;
}

 

 

      ArrayList 和其他相似类真正需要的是:客户端代码基于每个实例指定这些类要使用的具体数据类型的方式。 这样将不再需要向上强制转换为 T:System.Object,同时,也使得编译器可以进行类型检查。 换句话说,ArrayList 需要一个类型参数。 这正是泛型所能提供的。

 

2:集合的线程安全

     .NET Framework 1.0 中的集合,如常用的 ArrayListHashtable通过 Synchronized 属性(此属性返回与集合有关的线程安全包装)提供某种线程安全性。该包装的工作原理是:对每个添加或移除操作锁定整个集合。因此,每个尝试访问集合的线程必须一直等待,直到轮到它来获取锁。这是无法进行伸缩的,并且对于大型集合而言,将会导致性能显著降低。此外,这一设计并不能完全防止出现争用情况。

     在 System.Collections.Generic 命名空间中 .NET Framework 2.0 中引入的集合类。这些集合类包括 List<(Of <(T>)>)Dictionary<(Of <(TKey, TValue>)>) 等。与 .NET Framework 1.0 类相比,这些类提供的类型安全性和性能会更高。不过,.NET Framework 2.0 集合类不提供任何线程同步;当同时在多个线程上添加或移除项时,用户代码必须提供所有同步。

     枚举整个集合本质上不是一个线程安全的过程。若要确保枚举过程中的线程安全性,可以在整个枚举过程中锁定集合。若要允许多个线程访问集合以进行读写操作,则必须实现自己的同步或使用 System.Collections.Concurrent 命名空间中的线程安全集合类之一。System.Collections.Concurrent..::.ConcurrentQueue<(Of <(T>)>)System.Collections.Concurrent..::.ConcurrentStack<(Of <(T>)>) 类在枚举元素之前将为元素拍摄快照,以防止转变成另一个线程上的集合。System.Collections.Concurrent..::.ConcurrentDictionary<(Of <(TKey, TValue>)>) 类不拍摄快照。

System.Collections.Concurrent..::.BlockingCollection<(Of <(T>)>) 类提供一个名为 GetConsumingEnumerable 的枚举器方法,该方法通过在枚举项时将项从集合中移除来转变集合。

     那么,说到底,到底如何来实现自己的线程安全呢。可以提供一个static object synObj = new object(); 然后lock(synObj)。

2.1:Syncronized静态方法和SyncRoot实例属性的用法

     在许多的集合类中,都能看到Syncronized静态方法和SyncRoot实例属性,这两个单词的sync就显而易见的说明了是用来实现同步的,那么,它们内在的机制是什么?

     Syncronized方法用来创造一个新的对象的线程安全包装,例如:

     HashTable ht = HashTable.Syncronized(new HashTable());

     使用这个方法创造的ht对象保证了在多线程环境下,进行对象的添加、删除和解析的时候,系统自动为它创建锁定区域,这样,省去了手工进行线程安全的设置。

     但是,使用这个方法并不能保证枚举的同步,例如,一个线程正在删除或添加集合项,而另一个线程同时进行枚举,这时枚举将会抛出异常。所以,在枚举的时候,你必须明确锁定这个集合。这是,我们要锁定并不是集合类对象本身,我们要锁定的是它的SyncRoot对象,这是为什么呢?

     举例来说,一个集合类将数据存放在某些类型的内部数据结构,如果,这个类给予这个外面对这个数据结构的访问权,那么仅仅锁定集合对象是无用的,当然,大部分情况下,返回的SyncRoot就是它本身,但是,还是有一些例外,所以,我们如果我们并不能确定集合对象和SyncRoot之间的关系,那么我们还是锁定SyncRoot为最佳选择;

           lock(ht.SyncRoot)

          {

           //你可以安全的对ht进行枚举了

          }

   

3:选择集合类

考虑以下问题:

4:位集合

     位集合是其元素为位标志的集合。 因为每一元素都是一位,而不是一个对象,所以这些集合的行为与其他集合稍有不同。

     位集合非常适合用来存储布尔值类型。

     BitArray 类是一个集合类,该类中的容量始终与计数相同。 可通过增加 Length 属性将元素添加到 BitArray 中;通过减少 Length 属性来删除元素。 BitArray 类提供一些在其他集合中未提供的方法,包括允许使用筛选器一次修改多个元素的那些方法,例如 AndOrXorNotSetAll

     BitVector32 类是一种结构,它提供与 BitArray 相同的功能,但性能更快。 BitVector32 的性能较快的原因是:它是值类型,因而在堆栈上分配空间;而 BitArray 是引用类型,因而在堆上分配空间。

     BitVector32 可存储正好 32 位的数据,而 BitArray 可存储可变位数的数据。 BitVector32 既可存储位标志又可存储小整数,因此很适合不向用户公开的数据。 但是,如果所需位标志的数目未知、可变或大于 32,则可用 BitArray 取而代之。

     用默认构造函数创建一个BitVector32,其中所有的32位都初始化为false。构造函数传入的值如果为1,则结果会再加1,相当于结果没有变化,所以还是false,如果传入-1来表示结果做了取反的变化,其结果则为true。

 

练习:

1.You are writing a custom dictionary. The custom-dictionary class is named MyDictionary. You need to ensure   
that the dictionary is type safe.    Which code segment should you use? 
A. class MyDictionary : Dictionary<string, string>
B. class MyDictionary : HashTable
C. class MyDictionary : IDictionary
D. class MyDictionary { ... }     
Dictionary<string, string> t = new Dictionary<string, string>();
MyDictionary dictionary = (MyDictionary)t;
Answer: A,因为因为泛型集合Dictionary<string, string> 可以进行编译器类型检查,是类型安全的。

 

2.You are developing an application to assist the user in conducting electronic surveys. The survey consists of 25 
true-or-false questions. You need to perform the following tasks: Initialize each answer to true.Minimize the 
amount of memory used by each survey. Which storage option should you choose? 
A. BitVector32 answers = new BitVector32(1);

B. BitVector32 answers = new BitVector32(-1);
C. BitArray answers = new BitArray (1);
D. BitArray answers = new BitArray(-1);
Answer: B

 

3.You are writing a method that returns an ArrayList named al. You need to ensure that changes to the ArrayList 
are performed in a thread-safe manner. Which code segment should you use? 
A. ArrayList al = new ArrayList();lock (al.SyncRoot){     return al;}
B. ArrayList al = new ArrayList();lock (al.SyncRoot.GetType()){     return al;}
C. ArrayList al = new ArrayList();Monitor.Enter(al);Monitor.Exit(al);return al;
D. ArrayList al = new ArrayList();ArrayList sync_al = ArrayList.Synchronized(al);return sync_al;   
Answer: D,因为使用Synchronized方法可以返回一个线程安全的集合,A,B,C选项中的al对象并不是一个线程安全的集合。

 

4.You are creating an undo buffer that stores data modifications. You need to ensure that the undo functionality     
undoes the most recent data modifications first. You also need to ensure that the undo buffer permits the storage of  strings only. Which code segment should you use? 
A. Stack<string> undoBuffer = new Stack<string>();
B. Stack undoBuffer = new Stack();
C. Queue<string> undoBuffer = new Queue<string>();
D. Queue undoBuffer = new Queue();
Answer: A ,Stack<string> 为先进后出,并且是通过编译器检查类型string的集合,先进后出保证了撤销的顺序,后进的先撤销。

 

5.You need to create a method  to clear a Queue named q. Which code segment should you use? 

A. foreach (object e in q) {    q.Dequeue();}
B. foreach (object e in q) {     Enqueue(null);}
C. q.Clear();
D. q.Dequeue();
Answer: C

 

6.You need to select a class that is optimized for key-based item retrieval from both small and large collections.   
Which class should you choose?   
A. OrderedDictionary class 
B. HybridDictionary class
C. ListDictionary class
D. Hashtable class
Answer: B

备注:建议将HybridDictionary用于字典中的元素数量未知的情况。它利用了 ListDictionary 处理小集合时性能改善的优点,同时也可灵活地切换到处理较大集合时能力比 ListDictionary 更好的 Hashtable

 

7:List<T> 相比ArrayList有什么优点。

 答:添加到 ArrayList 中的任何引用或值类型都将隐式地向上强制转换为 Object。 如果项是值类型,则必须在将其添加到列表中时进行装箱操作,在检索时进行取消装箱操作。强制转换以及装箱和取消装箱操作都会降低性能;在必须对大型集合进行循环访问的情况下,装箱和取消装箱的影响非常明显。List<T>使用泛型指定了集合的类型,所以它是类型安全的,故不存在装箱和拆箱,效率更高。

8:对集合来说,什么是线程安全。不要照抄MSDN,举例说明。

答:如果多个线程同时需要访问同一个集合,那么这个集合需要当作互斥资源来对待,该集合同时只允许一个访问者对其进行访问,否者就不是一个线程安全的访问。
集合的线程安全分两类,一类是传统集合,如ArrayList,举例如下:
        ArrayList list = new ArrayList();
        void ThreadSafeFun()
        {
            for (int i = 0; i < 50; i++)
            {
                list.Add("abc");
            }
            for (int i = 0; i < 50; i++)
            {
                Thread tadd = new Thread(this.Add);
                tadd.Start();
                Thread tdel = new Thread(this.Del);
                tdel.Start();
            }
        }

        void Add()
        {
            while (true)
            {
                lock (list.SyncRoot)
                {
                    list.Add("abc");
                }
                Thread.Sleep(50);
            }
        }

        void Del()
        {
            while (true)
            {
                lock (list.SyncRoot)
                {
                    if (list.Count > 0)
                    {
                        list.RemoveAt(0);
                    }
                }
                Thread.Sleep(50);
            }
        }
一类是泛型集合,举例如下:
        List<string> tList = new List<string>();
        object lockObj = new object();
        void TThreadSafeFun()
        {
            for (int i = 0; i < 50; i++)
            {
                tList.Add("abc");
            }
            for (int i = 0; i < 50; i++)
            {
                Thread tAdd = new Thread(this.TAdd);
                tAdd.Start();
                Thread tDel = new Thread(this.TDel);
                tDel.Start();
            }
        }

        void TAdd()
        {
            while (true)
            {
                lock (lockObj)
                {
                    tList.Add("abc");
                }
                Thread.Sleep(50);
            }
        }

        void TDel()
        {
            while (true)
            {
                lock (lockObj)
                {
                    if (tList.Count > 0)
                    {
                        tList.RemoveAt(0);
                    }
                }
                Thread.Sleep(50);
            }
        }

 

9:写代码说明,在删除ArrayList中其中一项的时候,如何锁定集合。

答:查看第8题;

 

10:写代码说明,在删除List<T>其中一项的时候,如何锁定集合。

答:查看第8题;

 

11:Syncronized静态方法和SyncRoot实例属性的区别。

答:查看本文描述

分享到:
评论

相关推荐

    Visual C#学习笔记光盘

    简介:本书由浅入深地讲解Visual C# 2005编程知识,全书内容分为6篇,共27章,第一篇介绍Visual Studio 2005开发环境和C#基础,其中包括Visual C# 2005简介,C#语言基础,面向对象编程基础,数组类和集合类,...

    C# 集合应用

    C#编程相关,集合类应用,基本操作,入门级知识总结,学习笔记

    c#学习笔记.txt

    2. 在集合类中使用一个预定义的集合。 (2) throw 语句用于发出在程序执行期间出现反常情况(异常)的信号。throw 语句的形式为: throw [expression]; expression :异常对象。当在 catch 子句中再次引发当前异常...

    C#6.0学习笔记——从第一行C#代码到第一个项目设计(第一个包)

    本书既适合作为C#完全自学图书,也适合作为相关培训机构的培训教材或者高校计算机类专业C#语言课程的参考教材。这是第一个压缩包。第二个包地址:https://download.csdn.net/download/wosingren/10463468

    C#6.0学习笔记——从第一行C#代码到第一个项目设计(第二个包)

    本书既适合作为C#完全自学图书,也适合作为相关培训机构的培训教材或者高校计算机类专业C#语言课程的参考教材。这是第二个压缩包。第一个压缩包地址:https://download.csdn.net/download/wosingren/10463453

    c#学习笔记——学习心得

    C#中的各种名词: 常数:声明时用const修饰,是隐式静态类型 域:一个代表和某对象或类相关的变量的成员 字段:和属性相同,是用来存储对象的值,可以直接访问数据且不能对数据添加任何限制,但是属性不能且可以对...

    中美 IT 培训 C# Asp.net 笔记3

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    C# 反射映射学习笔记

    最近想研究一下反射,先上网找了找资料,几乎大部分都是照抄MSDN的内容,生涩难懂,几乎没说,又找了找,发现一些强人的实例...然后通过某种办法找到这个DLL集合中的某个空间下的某个类的某个成员(不管是公有还是私有)。

    中美 IT 培训 C# Asp.net 笔记2

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    中美 IT 培训 C# Asp.net 全套笔记1

    针对循环、数组、类的概念、类的构建、类的使用、对象的创建、面向对象的思想、集合、排序、IO操作等知识点先后安排2或3个小型项目:1。制作一个通讯录;2。制作一个小游戏;3。教学管理系统。 通过实际项目深入理解...

    net学习笔记及其他代码应用

    声明方法的存在而不去实现它的类被叫做抽象类(abstract class),它用于要创建一个体现某些基本行为的类,并为该类声明方法,但不能在该类中实现该类的情况。不能创建abstract 类的实例。然而可以创建一个变量,其...

    ASP升级.net资料大全(c#入门 语言规范 源码教程 学习笔记 技术资料 面试题 asp与.net代码生成器)

    C# Language Specification 1.2(C#语言规范1.2).doc C# Language Specification 2.0(C#语言规范2.0).doc 源码教程 ASP.NET编程技术与交互式网页设计 asp.net亲密接触_带源码 C#学习 01_类.htm.txt 02_构造函数...

    .net技术资料大全(语言规范 源码教程 学习笔记 技术资料 .net代码生成器)

    C# Language Specification 1.2(C#语言规范1.2).doc C# Language Specification 2.0(C#语言规范2.0).doc 源码教程 ASP.NET编程技术与交互式网页设计 asp.net亲密接触_带源码 C#学习 01_类.htm.txt 02_构造函数...

    C# 正则表达式经典分类整理集合手册第1/3页

    现在用到正则的时候也比较少,把以前的笔记等整理一下,以志不忘。

    asp.net知识库

    C#中结构与类的区别 C#中 const 和 readonly 的区别 利用自定义属性,定义枚举值的详细文本 Web标准和ASP.NET - 第一部分 XHTML介绍 在ASP.NET页面中推荐使用覆写(Override)而不是事件处理(Event Handler) 常用...

    数据库系统原理——ER模型与关系模型(1).pdf

    (ER模型中的实体往往是指实体集) 实体集:指同⼀类实体构成的集合 实体⽤⽅框表⽰表⽰,⽅框内注明实体的命名。 联系:表⽰⼀个或多个实体之间的关联关系。 联系⽤菱形框表⽰,并⽤线段将其与相关的实体链接起来 ...

    Extjs学习笔记之九 数据模型(上)

    数据集 Store 一个保存数据的集合,类似于C#的Datatable。 Extjs3的Proxy较以前版本有了一些变动,资料很少,而且官方文档上相当简练,以至于一个完整的例子都没有…… 我尽力理解…… 1. 数据记录 一条数据记录...

    值类型与引用类型理论内容.part01.rar

    ASP.NET培训资料(笔记版)(AJAX,C#,JavaScript,SQL) 详细的资料 三个月的课程录像+资料笔记(花了一万六千块的培训资料超值【19G的经典内容】 认真学习后包你能成为优秀的.net程序员 &lt;br&gt;(注明:不是...

    值类型与引用类型理论内容.part05.rar

    ASP.NET培训资料(课堂视频含笔记)(AJAX,C#,JavaScript,SQL) &lt;br&gt;我将不定期发布,直至所有课程完毕 &lt;br&gt;详细的资料 三个月的课程录像+资料笔记(花了一万六千块的培训资料超值【19G的经典内容】 认真...

Global site tag (gtag.js) - Google Analytics