2007年3月28日星期三

ReadOnlyCollection :threadsafe and readonly

为了让对象是只读的可以将其标示为ReadOnly的,但是如果这样做的话我们的对象就只能在构造函数中初始化,在其他的地方没办法操作了,这往往都不是我们所希望的。有一种做法是我们让对象是可以修改的,但是当没有权限操作(或说不应该修改)它的对象获得它的引用(一定是引用,值传递没这个问题)的时候我们就返回一个对象那个的Copy,比如

public abstract class OperationBase : IOperation
{
public OperationBase(AppPart appPart)
{
this.appPart = appPart;
}

……

public AppPart AppPart
{
get
{
//protect this appPart from being modified
return (AppPart)appPart.Clone();
}
//set
//{
// appPart = value;
//}
}

……

protected AppPart appPart;

……

}

这样其实不是真正的只读(ReadOnly),只不过对“Clone对象”的修改都不会影响到“源对象”而已。对于简单的对象这样做没有问题,但是如果“大对象”比如集合,要Clone的代价就比较大了,所以我们不简单的返回Clone。我们可以自己设计一个集合让它实现IEnumerable接口,但是内部存储使用一个集合,但是这样又带来一个问题,很多集合的操作我们无法使用了,因为IEnumarable接口提供的方法太少。其实.net2.0提供了一个解决方法——“ReadOnlyCollection”,

An instance of the ReadOnlyCollection generic class is always read-only. A collection that is read-only is simply a collection with a wrapper that prevents modifying the collection; therefore, if changes are made to the underlying collection, the read-only collection reflects those changes.

Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.

A ReadOnlyCollection can support multiple readers concurrently, as long as the collection is not modified.
上面是MSDN的介绍,我们可以看到它不仅是只读的,而且静态实例对于“读操作还是线程安全”,前提是读的同时没有线程去修改该集合内部的集合(正真存储了数据的集合)。ReadOnlyCollection其实只是对普通结合的一个包装,将一些修改的操作屏蔽掉了。
public class ReadOnlyCollection : IList, ICollection, IEnumerable, IList, ICollection, IEnumerable
ReadOnlyCollection的定义说明它实现了像Ilsit,ICollection这样的接口,但是他们是有修改操作的比如Add,Insert,Remove,如果我们对ReadOnlyCollection的实例做强制类型转换在操作会有什么结果:
ReadOnlyCollection readonlyColl = new ReadOnlyCollection(userList);
((IList)readonlyColl).Add(new User());
如果运行这段代码会报错“Not supported exception”,这说明该集合的实现与一般的集合有所不同,CLR的实现者对这个做了特殊的处理。

最后说一个问题,如何对获得只读集合进行排序?我们无法排序,因为无法操作集合,如果要排序的话只能将集合的元素复制到自己的新集合中,在排序:
readonlyColl.CopyTo(new User[readonlyColl.Count],0);

没有评论: