19.3.2 ReadOnlyCollectionBase
如果需要创建一个只读集合,就只能扩展ReadOnlyCollectionBase基类了。该类也提供了一个名为InnerList的属性,此属性是只读属性。实际上,真正负责存储数据的是基类中私有变量list。InnerList属性返回的是一个ArrayList类型的变量,此属性的get访问器会检查私有变量list是否为null,如果是就先实例化它,再返回实例化后的list变量;否则直接返回list变量,如下所示:
protected ArrayList InnerList
{
get
{
if(this.list==null)
{
this.list=new ArrayList();
}
return this.list;
}
}
注意,此属性的访问级别是protected,只能被ReadOnlyCollectionBase类自己以及它的派生类使用。因为要自定义一个只读的集合类型,因此派生类必须确保基类中的list集合变量中的数据不被修改。
作为示例,我们定义了一个名为Students的只读集合。再次提醒大家,此时定义的是一个只读集合,因此要特别注意如下几个问题:
❑不要提供能改变集合中数据的方法,例如Add、Remove等。
❑不要提供默认构造函数,因为有了默认构造函数就可以直接实例化集合类型,那么集合中数据何时初始化呢?如果放在默认构造函数中,那么得到的将是一个永远都是不变的数据的只读集合,这显然不是我们的初衷所在。
❑要提供一个带参数的构造函数,在集合初始化的同时初始化集合中的数据,因为没有改变集合数据的方法,因此集合在实例化后就再也不允许改变了。
代码清单19-15 演示了如何定义一个自定义集合。
代码清单19-15 使用ReadOnlyCollectionBase自定义集合代码示例
using System;
using System.Collections;
namespace ProgrammingCSharp4
{
class CollectionSample
{
public static void Main()
{
IList stuList=new ArrayList();
stuList.Add(new Student{Name="Tom",Sex="Male"});
stuList.Add(new Student{Name="Alice",Sex="Female"});
stuList.Add(new Student{Name="Jack",Sex="Male"});
Students students=new Students(stuList);
PrintCollectionInfo(students,"students");
}
public class Students:ReadOnlyCollectionBase
{
//带参数的构造函数,在集合初始化的同时初始化数据
public Students(ICollection students)
{
InnerList.AddRange(students);
}
public int IndexOf(Object student)
{
return(InnerList.IndexOf(student));
}
public bool Contains(Object student)
{
return(InnerList.Contains(student));
}
//索引器
public Object this[int index]
{
get
{
return(InnerList[index]);
}
}
}
public class Student
{
public string Name{get;set;}
public string Sex{get;set;}
public string Grade{get;set;}
public DateTime Birthday{get;set;}
}
private static void PrintCollectionInfo(Students stuList,string varName)
{
Console.Write("{0}:",varName);
foreach(Student student in stuList)
{
Console.Write("\t{0}",student.Name);
}
Console.WriteLine();
Console.WriteLine("Count:{0}",stuList.Count);
}
}
}
上述代码的运行结果为:
students:Tom Alice Jack
Count:3
请按任意键继续……