We use collections all the time. Many times we have to expose them to users of our classes. Lets look at this simple tree node class:
class TreeNode { private List<TreeNode> children = new List<TreeNode>(); public IList<TreeNode> Children { get { return children; } } }
The children need to be accessed by who ever uses our TreeNode, but are they allowed to add new tree nodes to the collection? Not necessarily. We might want to control it inside the TreeNode class. So how to expose the children as read only? very simple, use the ReadOnlyCollection class.
The ReadOnlyCollection is simply a read only wrapper to the collection, that prevents modifying the original collection. It does not create new objects but holds the original collection, so any changes to the original collection will be reflected in the read only collection. The ReadOnlyCollection implements few interfaces: IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable. The implementation is straight forward: for every function that changes the original collection an exception is thrown, otherwise return the result of calling the same function on the original collection.
The List<T> has a AsReadOnly method that will simply returns the read only wrapper of the current collection.
Lets see the safe version of the TreeNode:
class TreeNode { private List<TreeNode> children = new List<TreeNode>(); public IList<TreeNode> Children { get { return children.AsReadOnly(); } } }
So its very easy to expose collections as read only, why don’t you do it?
By Poul on Apr 10, 2008 | Reply
ReadOnlyCollection is great, but only enforces readonly at runtime, exposing collections as IEnumerable enforces readonly at compiletime.
And if you for some reason needs to use the indexer, simply use new List(collection)
By Shahar A on Apr 10, 2008 | Reply
I Agree if you can work with IEnumarable its even better. However, if you create new List(collection) objects will be copied into the new list, and new list can be change with no reflection to the original one which might be dangarous…
By Yaswanth on Apr 10, 2008 | Reply
Is there any similar this in Java ?
By Yaswanth on Apr 10, 2008 | Reply
Is there any similar thing in JAVA ?
By Judah on Apr 10, 2008 | Reply
I agree with Poul, exposing as IEnumerable is best, since it gives you compile-time verification. Also, list.AsReadOnly actually allocates a new object behind the scenes, exposing as IEnumerable does not.
By Will on Apr 10, 2008 | Reply
Probably because its not always appropriate.
By Kit Anderson on Apr 11, 2008 | Reply
@Yaswanth, it would be possible to create your own wrapper, extending the collection you wish to protect, and re implement the ‘write’ functions to throw exceptions, while the ‘read’ functions can call the original parent class functions.
By Ben on Apr 11, 2008 | Reply
Yes, java.util.Collections introduced this into the language about a decade ago.