NET FrameWork的Collections支持
笔记: 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);
}
SyncRoot及IsSynchronized属性代表此Collection是否支持同步处理,当Collection支持同步处理时,实现IsSynchronized时返回True,并在SyncRoot中返回一个对象引用作为lock时所使用的对象。
IList接口
到这里之前提到的Collection接口还不具备修改、删除元素的能力。IList接口正是提供了修改、删除元素的能力,但是这种能力也有限制。IList 是 继承自ICollection 接口,并且是所有列表的抽象基类。IList 实现有三种类别:只读、固定大小、可变大小。无法修改只读 IList。固定大小的 IList 不允许添加或移除元素,但允许修改现有元素。可变大小的 IList 允许添加、移除和修改元素。
public interface IList: ICollection, IEnumerable
{
object this[int index] {get; set;}
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]
我们常用Hashtable、ArrayList类,也就是IDictionary和IList接口,它们的元素都是object,而.NET Framework所有的对象皆源自object,Collection这表示可以放入所有对象类型。这样的结构是最具有扩展性的设计方式,但是另一个方面,这种设计方式似乎过于松散,容易产生混淆和误,也不好针对独特的应用进行优化。所以,在.NET Framework中就有强类型的Collection的实现。强类型的Collection是指对每一个元素操作Interface进行限定类型。比如IList的Add封装的实现:
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均为string的Collection。其中value可通过Key或Index来访问。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 也将返回它所设置成的元素。
枚举数没有对集合的独占访问权;因此,枚举一个集合在本质上不是一个线程安全的过程。甚至在对集合进行同步处理时,其他线程仍可以修改该集合,这会导致枚举数引发异常。若要在枚举过程中保证线程安全,可以在整个枚举过程中锁定集合,或者捕捉由于其他线程进行的更改而引发的异常。


浙公网安备 33010602011771号