程序中的阿呆

经常做做梦,写写工作无关代码
  首页  :: 新随笔  :: 订阅 订阅  :: 管理

NET FrameWork的Collections支持

Posted on 2005-12-05 23:49  MicroDream  阅读(1951)  评论(6)    收藏  举报
 

NET FrameWorkCollections支持
笔记: SeanX 

Collection是指集合,具有能枚举的特性,是一群元素的容器。.NET Framework中提供了详细的接口定义和实现方式。 

IEnumerable接口

IEnumerable是最基本的Collection接口,所以Collection类都必须实现此接口,它声明的成员就只有一个: GetEnumerator,实现该接口在此函数必须返回一个IEnumerator的对象。

public interface IEnumerable
{
   IEnumerator GetEnumerator();
}

IEnumerator接口

IEnumerator 是所有枚举数的基接口。sIEnumerator接口主要应用于枚举Collection元素,实现该接口才基本具有遍历、枚举元素的能力,但是它采用只能往前不能退后的枚举方式,从下面的Interface定义就可以明显看出:

public interface IEnumerator

   
object Current get;}
   
bool MoveNext();
   
void Reset();
}



只要实现了IEnumerator接口的对象,就可以使用于C#foreach语法。

 

ICollection接口 

ICollection接口是IEnumerable的加强型接口,继承自IEnumerable接口,增加了同步处理、复制和返回Collection内元素个数的功能。ICollection 接口是 System.Collections 命名空间中类的基接口。

public interface ICollection: Inumberable

{

   int Count {get; }

   object SyncRoot {get;}

   bool IsSynchronized {get;}

   void CopyTo(Array array, int index);

}

SyncRootIsSynchronized属性代表此Collection是否支持同步处理,当Collection支持同步处理时,实现IsSynchronized时返回True,并在SyncRoot中返回一个对象引用作为lock时所使用的对象。

 

IList接口

到这里之前提到的Collection接口还不具备修改、删除元素的能力。IList接口正是提供了修改、删除元素的能力,但是这种能力也有限制。IList 继承自ICollection 接口,并且是所有列表的抽象基类。IList 实现有三种类别:只读、固定大小、可变大小。无法修改只读 IList。固定大小的 IList 不允许添加或移除元素,但允许修改现有元素。可变大小的 IList 允许添加、移除和修改元素。

 

public interface IList: ICollection, IEnumerable
{
object this[int index] {getset;}
bool IsReadOnly {get; }
bool IsFixedSize {get;}
int Add(object value);
bool Contains(object value);
void Clear();
int IndexOf(object value);
void Insert(int index, object value);
void Remove(object value);
void RemoveAt(int index);
}

IDictionary接口

 

public interface IDictionary : ICollection, IEnumerable

{

object this[int index] {get; set;}
        bool IsReadOnly {get; }

bool IsFixedSize {get;}

ICollection Keys {get;}

ICollection Values {get;}

IDictionaryEnumerator GetEnumerator();

int Add(object value);

bool Contains(object value);

void Clear();

int IndexOf(object value);

void Insert(int index, object value);

void Remove(object value);

void RemoveAt(int index);

}

IDictionary 类是键/值对的集合的基接口。

每个元素是一个存储在 DictionaryEntry 对象中的键/值对,如 Hashtable 类。每个关联必须具有非空引用的唯一键,但关联的值可以为任何对象引用,包括空引用 (Nothing)IDictionary 接口允许对所包含的键和值进行枚举,但这并不意味着任何特定的排序顺序。IDictionary 也实现有三种类别:只读、固定大小、可变大小。无法修改只读 IDictionary。固定大小的 IDictionary 不允许添加或移除元素,但允许修改现有元素。可变大小的 IDictionary 允许添加、移除和修改元素。

C# 语言中的 foreach 语句需要集合中每个元素的类型。由于 IDictionary 的每个元素都是一个键/值对,因此元素类型既不是键的类型,也不是值的类型。而是 DictionaryEntry 类型。例如:

foreach (DictionaryEntry myDE in myHashtable) {...}

注意:

foreach 语句是对枚举数的包装,它只允许从集合中读取,不允许写入集合。

DictionaryEntry 实现IDictionaryEnumerator接口,IDictionaryEnumerator接口是枚举字典的元素结构,继承自IEnumerator,增加了Key/Value属性来读取每一个字典。 

强类型Collection [Strong-Type Collection]

我们常用HashtableArrayList类,也就是IDictionaryIList接口,它们的元素都是object,而.NET Framework所有的对象皆源自objectCollection这表示可以放入所有对象类型。这样的结构是最具有扩展性的设计方式,但是另一个方面,这种设计方式似乎过于松散,容易产生混淆和误,也不好针对独特的应用进行优化。所以,在.NET Framework中就有强类型的Collection的实现。强类型的Collection是指对每一个元素操作Interface进行限定类型。比如IListAdd封装的实现:

public int Add(string value)

{

   Return ((IList)this).Add(value);

}

这样就要求对象使用者只能增加string类别的元素。

在命名空间System.Collections.Specialized内定义了数个强类型的类,下面说明常用的:

StringDictinary: Key的型别被限定为string, 并且区分大小写

ListDictionary: 这也是IDictionary的一个实现,以单向链表完成。如果元素个数不超过10个,比Hashtable更小且更快(测试感觉不出,可能才10个的原因)

NameValueCollection: 一个已经排序且Key/Value均为stringCollection。其中value可通过KeyIndex来访问。NameValueCollection可以在单个Key之下存储多个stirng values 

.NET Framework为强类型集合提供抽象的基类CollectionBase(.NET 2.0有所改变?),提供此基类旨在使Framewrok用户创建强类型自定义集合变得更容易。我们应扩展此基类,而不应创建自己的基类。

CollectionBase 实例始终是可修改的,另有不可修改版本的ReadOnlyCollectionBase基类。

 

总结和线程安全

IDictionary IList 是基于 ICollection 接口的更专用的接口。IDictionary 实现是键/值对的集合,如 Hashtable 类。IList 实现是可被排序且可按照索引访问其成员的值的集合,如 ArrayList 类。某些集合(如 Queue 类和 Stack 类)限制对其成员的访问,它们直接实现 ICollection 接口。

如果 IDictionary 接口和 IList 接口都不能满足所需集合的要求,则从 ICollection 接口派生新集合类以我们的要求和个性化特性。

枚举数只允许读取集合中的数据。枚举数无法用于修改基础集合。

最初,枚举数被定位于集合中第一个元素的前面。Reset 也将枚举数返回到此位置。在此位置,调用 Current 会引发异常。因此,在读取 Current 的值之前,必须调用 MoveNext 将枚举数提前到集合的第一个元素。

在调用 MoveNext Reset 之前,Current 返回同一对象。MoveNext Current 设置为下一个元素。

在传递到集合的末尾之后,枚举数放在集合中最后一个元素后面,且调用 MoveNext 会返回 false。如果最后一次调用 MoveNext 返回 false,则调用 Current 会引发异常。若要再次将 Current 设置为集合的第一个元素,可以调用 Reset,然后再调用 MoveNext

只要集合保持不变,枚举数就保持有效。如果对集合进行了更改(例如添加、修改或删除元素),则该枚举数将失效且不可恢复,并且下一次对 MoveNext Reset 的调用将引发 InvalidOperationException。如果在 MoveNext Current 之间修改集合,那么即使枚举数已经无效,Current 也将返回它所设置成的元素。

枚举数没有对集合的独占访问权;因此,枚举一个集合在本质上不是一个线程安全的过程。甚至在对集合进行同步处理时,其他线程仍可以修改该集合,这会导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。