购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

建议23:避免将List<T>作为自定义集合类的基类

如果要实现一个自定义的集合类,不应该以一个FCL集合类为基类,而应该扩展相应的泛型接口。FCL集合类应该以组合的形式包含至自定义的集合类,需扩展的泛型接口通常是IEnumerable<T>和ICollection<T>(或ICollection<T>的子接口,如IList<T>),前者规范了集合类的迭代功能,后者则规范了一个集合通常会有的操作。

在一般情况下,下面两个实现的集合类都能完成默认的需求:


class Employees1:List<Employee>

class Employees2:IEnumerable<Employee>,ICollection<Employee>


不过,遗憾的是,List<T>基本上没有提供可供子类使用的protected成员(从object中继承来的Finalize方法和MemberwiseClone方法除外),也就是说,实际上,继承List<T>并没有带来任何继承上的优势,反而丧失了面向接口编程带来的灵活性。而且,稍加不注意,隐含的Bug就会接踵而至。

以Employees1为例,如果要在Add方法中加入某些需求方面的变化,比如,这个变化是为名字添加一个后缀"Changed",但是客户端的开发人员也许已经习惯了面向接口的编程方式,他在为集合添加一个元素的时候使用了如下的语法:


static void Main(string[]args)

{

Employees1 employees1=new Employees1()

{

new Employee(){Name="Mike"},

new Employee(){Name="Rose"}

};

IList<Employee>employees=employees1;

employees.Add(new Employee(){Name="Steve"});

foreach(var item in employees1)

{

Console.WriteLine(item.Name);

}

}

class Employee

{

public string Name{get;set;}

}

class Employees1:List<Employee>

{

public new void Add(Employee item)

{

item.Name+="Changed!";

base.Add(item);

}

}


于是,代码的实际输出会偏离集合类的设计者的设想。以上代码的输出为:


Mike Changed!

Rose Changed!

Steve


要纠正这类非预期的行为,我们应该采用Employees2的方式:


static void Main(string[]args)

{

Employees2 employees2=new Employees2()

{

new Employee(){Name="Mike"},

new Employee(){Name="Rose"}

};

ICollection<Employee>employees=employees2;

employees.Add(new Employee(){Name="Steve"});

foreach(var item in employees2)

{

Console.WriteLine(item.Name);

}

}

class Employees2:IEnumerable<Employee>,ICollection<Employee>

{

List<Employee>items=new List<Employee>();

#region IEnumerable<Employee>成员

public IEnumerator<Employee>GetEnumerator()

{

return items.GetEnumerator();

}

#endregion

#region ICollection<Employee>成员

public void Add(Employee item)

{

item.Name+="Changed!";

items.Add(item);

}

//省略

#endregion

}


以上代码的输出为:


Mike Changed!

Rose Changed!

Steve Changed! UxoaQx5nkvFJeqBGJM3elMMkbqEPkd5TcPW9qEKcpvBGqnPv323dWRoBCJVAOd3O


点击中间区域
呼出菜单
上一章
目录
下一章
×

打开