C#集合--ICollection接口和IList接口
虽然列举接口提供了一个协议,用于向前的方式遍历集合,但它们没有提供一种机制来确定集合的大小,通过索引访问集合的成员,搜索集合,或修改集合。为了实现这些功能,.NET Framework定义了ICollection,IList和IDictionary接口。每个接口都有Generic的接口和非Generic的接口,请注意非Generic多数用于支持遗留代码。
这些接口的继承挂关系如下图所示:

Generic的接口和非Generic的接口之间的差距超出了你的预期,特别是ICollection和ICollection<T>。这是由于历史原因造成的,因为Generic类型是C# 2.0才引入的,所以Generic吸取了非Generic接口的经验和教训,从而设计了与之不同的但更优秀的接口。正式由于这个原因,ICollection<T>并没有派生自ICollection,同样地,IList<T>也没有派生自IList, IDictionary<TKey,TValue>也没有派生自IDinctionary。因此集合类可以同时实现Generic的接口和非Generic的接口。(事实上,集合类一般都实现了两个类型接口,比如class Collection<T>: IList<T>, IList,有比如List<T> : IList<T>, System.Collections.IList)。
ICollection<T>和ICollection
ICollection<T>是可以统计集合中对象的标准接口。该接口可以确定集合的大小(Count),集合是否包含某个元素(Contains),复制集合到另外一个数组(ToArray),集合是否是只读的(IsReadOnly)。如果一个集合是可编辑的,那么可以调用Add,Remove和Clear方法操作集合中的元素。因为该接口继承IEnumerable<T>,所以可以使用foreach语句遍历集合。该接口的定义如下
public interface ICollection<T> : IEnumerable<T>
{
// Number of items in the collections.
int Count { get; } bool IsReadOnly { get; } void Add(T item); void Clear(); bool Contains(T item); // CopyTo copies a collection into an Array, starting at a particular
// index into the array.
//
void CopyTo(T[] array, int arrayIndex); //void CopyTo(int sourceIndex, T[] destinationArray, int destinationIndex, int count); bool Remove(T item);
}
而非Generic的ICollection定义如下:
public interface ICollection : IEnumerable
{
void CopyTo(Array array, int index); int Count { get; } Object SyncRoot { get; } bool IsSynchronized { get; }
}
与ICollection<T>相比较,ICollection实现了计算集合元素数目的功能,但明没有提供更改集合的功能。此外,ICollection还提供了同步的功能。而ICollection<T>则取消了同步的功能,这是因为对于Generic的集合,它们本身是线程安全的。
这两个接口既简单又容易实现。假如要实现一个只读的ICollection<T>,那么在Add,Remove,和Clear方法中抛出异常即可。
这些接口通常与任何IList或IDictionary接口中的任意一个一起实现。
IList<T>和IList
如果想通过位置获取集合元素,那么IList<T>就是此类集合的标准接口。此外,由于IList<T>继承了ICollection<T>和IEnumerable<T>,所以此接口还提供了根据位置读取或写入元素,或者在指定的位置插入或删除元素。IList<T>定义如下
public interface IList<T> : ICollection<T>
{
T this[int index] { get; set; } int IndexOf(T item); void Insert(int index, T item); void RemoveAt(int index);
}
IndexOf方法在集合上执行线性搜索,如果没有发现指定元素,那么返回-1。
List类的IndexOf方法的实现:(List.IndexOf(T item)调用Array.IndexOf(_items, item, index, _size - index),然后调用EqualityComparer<T>.Default.IndexOf(array, value, startIndex, count))
internal virtual int IndexOf(T[] array, T value, int startIndex, int count) {
int endIndex = startIndex + count;
for (int i = startIndex; i < endIndex; i++) {
if (Equals(array[i], value)) return i;
}
return -1;
}
而非Generic的IList则包含了更多成员,因为它继承ICollection
public interface IList : ICollection
{
Object this[int index] { get;set; }
int Add(Object value);
bool Contains(Object value);
void Clear();
bool IsReadOnly { get; }
bool IsFixedSize { get; }
int IndexOf(Object value);
void Insert(int index, Object value);
void Remove(Object value);
void RemoveAt(int index);
}
IList接口的Add方法返回一个整数,这是加到集合中元素的位置。而IList<T>接口的Add方法返回值为空。
C#中,List<T>就是典型的既实现了IList<T>又实现了IList的类。
public class List<T> : IList<T>, System.Collections.IList, IReadOnlyList<T>
C#数组也实现了generic和非generic的IList接口。C#中Array类的部分代码(实现IList接口的代码)
public abstract class Array : ICloneable, IList, IStructuralComparable, IStructuralEquatable
{
......
public bool IsReadOnly
{ get { return false; } } public bool IsFixedSize
{
get { return true; }
} Object IList.this[int index]
{
get { return GetValue(index); }
set { SetValue(value, index); }
} int IList.Add(Object value)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
} bool IList.Contains(Object value)
{
return Array.IndexOf(this, value) >= this.GetLowerBound(0);
} void IList.Clear()
{
Array.Clear(this, this.GetLowerBound(0), this.Length);
} int IList.IndexOf(Object value)
{
return Array.IndexOf(this, value);
} void IList.Insert(int index, Object value)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
} void IList.Remove(Object value)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
} void IList.RemoveAt(int index)
{
throw new NotSupportedException(Environment.GetResourceString("NotSupported_FixedSizeCollection"));
}
......
}
而Generic的IList<T>是在sealed class SZArrayHelper中实现的。SZ(Single dimensional, Zero-based)。请注意,如果你在技术与上调用add或者remove方法,那么会返回NotSupportedException异常

IReadonlyList<T>
为了与Windows运行时的制度集合互操作,Framework4.5引入了一个新的集合接口IReadOnlyList<T>。该接口自身就非常有用,也可以看作IList的缩减版,对外只公开用于只读的操作。其定义如下:
public interface IReadOnlyCollection<out T> : IEnumerable<T>
{
int Count { get; }
} public interface IReadOnlyList<out T> : IReadOnlyCollection<T>
{
T this[int index] { get; }
}
因为类型参数仅仅用于输出位置,所以其标记为协变(covariant)。比如,一个cats列表,可以看作一个animals的只读列表。相反,在IList<T>中,T没有标记为协变,因为T应用于输入和输出位置。
你可能认为IList<T>派生自IReadonlyList<T>,然后,微软并没有这么做,这是因为这么做就要求把IList<T>的成员移动到IReadonlyList<T>,这就给CLR4.5带来重的变化(程序员需要重新编辑程序以避免运行时错误)。实际上,微软在IList<T>的实现类中手动地添加了对IReadonlyList<T>接口的实现。
在Windows运行时中IVectorView<T>与.NET Framework的IReadonlyList<T>相对应。
参考
线性搜索(Linear Search): http://en.wikipedia.org/wiki/Linear_search; http://blog.teamleadnet.com/2012/02/quicksort-binary-search-and-linear.html
数组实现IList<T>: http://stackoverflow.com/questions/11163297/how-do-arrays-in-c-sharp-partially-implement-ilistt/11164210#11164210
数组的奥秘: http://stackoverflow.com/questions/19914523/mystery-behind-system-array
C#集合--ICollection接口和IList接口的更多相关文章
- 服务器文档下载zip格式 SQL Server SQL分页查询 C#过滤html标签 EF 延时加载与死锁 在JS方法中返回多个值的三种方法(转载) IEnumerable,ICollection,IList接口问题 不吹不擂,你想要的Python面试都在这里了【315+道题】 基于mvc三层架构和ajax技术实现最简单的文件上传 事件管理
服务器文档下载zip格式 刚好这次项目中遇到了这个东西,就来弄一下,挺简单的,但是前台调用的时候弄错了,浪费了大半天的时间,本人也是菜鸟一枚.开始吧.(MVC的) @using Rattan.Co ...
- Java集合中Comparator和Comparable接口的使用
在Java集合中,如果要比较引用类型泛型的List,我们使用Comparator和Comparable两个接口. Comparable接口 -- 默认比较规则,可比较的 实现该接口表示:这个类的实例可 ...
- java集合 之 Collection和Iterator接口
Collection是List,Queue和Set接口的父接口,该接口里定义的方法即可用于操作Set集合,也可以用于List和Queue集合.Collection接口里定义了如下操作元素的方法. bo ...
- 3.Java集合总结系列:Set接口及其实现
一.Set接口 Set 接口与 List 接口相比没有那么多操作方法,比如: 1.List 接口能直接设置或获取某个元素的值,而Set接口不能. 2.List 接口能直接在指定位置删除.增加元素,而S ...
- 2.Java集合总结系列:List接口及其实现
在介绍List接口之前,我们先来看看 Collection 接口,因为Collection接口是 List / Set / Queue 接口的父接口,List / Set / Queue 的实现类中很 ...
- C# 通过IEnumberable接口和IEnumerator接口实现自定义集合类型foreach功能
1.IEnumerator和IEnumerable的作用 其实IEnumerator和IEnumerable的作用很简单,就是让除数组和集合之外的类型也能支持foreach循环,至于foreach循环 ...
- Java学习笔记30(集合框架四:List接口)
List接口继承自Collection接口 具有重要的三大特点: 1.有序集合:存入和取出的顺序一致 2.此接口的用户可以对列表中每个元素插入位置精确的控制:可以通过索引操作 3.可以存储重复元素 L ...
- 集合(1)—List接口的实现类ArrayList
List List接口是Collection接口的子接口,从其名称可以看出,是一个元素有序(并不是按大小排序,具有顺序索引,类似于数组),默认按照元素的添加顺序设置元素的索引. List用法 List ...
- Spring @Autowired注解用在集合上面,可以保持接口的所有实现类
CourseService课程接口有2个子类,HistroyCourseServiceImpl和MathsCourseServiceImpl public interface CourseServic ...
随机推荐
- git 使用笔记
git操作: git checkout 分支名称 // 切换分支git branch -a // 查看分支信息和当前分支 git pull // 将服务器所有代码下载到本地git merge orig ...
- 我的WebService入门
ERP: 1. Data Layer: (ProductInfoDBHelper.cs) /// <summary> /// 获取门店图片信息 /// </summary> p ...
- Orchard Compact v1.7.2
1. 仅包留了Core中的Settings和Shapes, 及Modules, Themes和jQuery模块. 2. 添加了对Oracle的支持. 下载地址: 二进制: Orchard.Compac ...
- Linux在Hyper-V中实现与Windows的宽带共享上网
相信不少读者都会做(或者曾经做过)这么一项活动——把一个Linux系统安装到Windows系统下的虚拟机软件中,然后在Windows这个大环境中对Linux进行学习或者一些实验操作.在进行这么一项活动 ...
- Python中文字符串截取
#-*- coding:utf8 -*- s = u'中文截取' s.decode('utf8')[0:3].encode('utf8') # 结果u'中文截取 延伸阅读: UTF-8中的汉字占用多少 ...
- Unity2.0容器自动注册机制
现如今可能每个人都会在项目中使用着某种 IoC 容器,并且我们的意识中已经形成一些固定的使用模式,有时会很难想象如果没有 IoC 容器工作该怎么进展. IoC 容器通过某种特定设计的配置,用于在运行时 ...
- Html5 学习系列(六)Html5本地存储和本地数据库
一个网站如何能在客户的浏览器存储更多的数据呢? 在Html4的时代在浏览器端存储点网站个性化的数据,尤其是用户浏览器的痕迹,用户的相关数据等一般只能存储在Cookie中,但是大多是浏览器对于Cooki ...
- 从数组中选出和等于固定值的n个数(JavaScript实现)
现实生活中的问题,可能会抽象为这样一种数据模型: 从一个数组中挑选出几个数,让这几个数相加的和为指定的值. 大多数读者应该有过网购的经历,网购一般会有个凑单功能,假如读者买了70元的商品,但是必须满1 ...
- HTML5 ——本地存储
目录 一.HTML4客户端存储 1.1.提交表单发送到服务器的信息 1.2.客户端本地存储概要 二.localStorage 2.1.添加 2.2.取值 2.3.修改 2.4.删除 2.5.跨页面与跨 ...
- 关于解决keil4和mdk共存后51不能使用go to definition Of 'XXXXXX'问题
自己安装keil4和mdk共存后,(我是先安装的keil 后安装的 MDK),在51单片机工程里不能使用go to definition Of 'XXXXXX'问题, 类似的如图 已经困扰了好长时间, ...