Sometimes it's necessary to expose an internal collection from an object to a hosting object. However, usually your object wants to control the changes to the collection. You can easily pass an array to the hosting object using the ToArray method, but that array is static to the hosting object. What if the hosting object needs updates?
The best way to illustrate the problem is with an example. In this example, I have a simple Windows Forms project with a Form that has an Infragistics UltraWinGrid (although any data grid will work that supports binding to an IList). I prefer not to expose internal controls to objects such as presenters in an MVP pattern, so that means my data which is not based on a database needs to be stored in another class or within the Form class, and I certainly don't like the latter option.
It just so happens that my object which I'll call a manager is responsible for the collection and for performing work based on the contents of the collection. The work being done is irrelevant for this article, but if you're curious I am spawning a separate thread which contacts a legacy application via TCP and submits jobs/requests for printing (after they've been processed through a workflow). The manager exposes some modification methods such as AddRequest, CancelRequest, et al. And those methods are the only way I want the outside world to modify the collection. But, at the same time the data grid needs to have access to the current data without needing to requery the property.
Enter the AsReadyOnly method. This method exposed by the List<T>, Set<T>, Array, and others generates what is basically an adapter to your collection. The return value is a System.Collections.ObjectModel.ReadOnlyCollection<T> that is the best of both worlds -- it shows live data from the internal collection and it doesn't let the consumer modify the collection contents.
Here's an example of the implementation
public class MyManagerClass
{
private List<MyObject> _objects = new List<MyObject>();
public ReadOnlyCollection<MyObject> Objects
{
get { return _objects.AsReadOnly(); }
}
}