In this post we are going to discuss about some new interfaces implemented by ReadOnlyCollection<T> in .net framework 4.5. We are oing to discuss how they can help us. If you look at the definition of ReadOnlyCollection<T> in the framework, you would notice these additional interfaces being implemented. We discussed about ReadOnlyCollection<T> in our discussion about purely functional data structures. The updated definition of ReadOnlyCollection<T> in .net framework 4.5 is as follows:
You might have seen ReadOnlyCollection<T>(s) as the return type of methods. It is used to provide a readonly wrapper around an IList<T>. Although they are not thread safe if the underlying collection's elements count are being continously updated. They makes it impossible for the outside scope to temper the collection by introducing or removing elements as these operations cause exceptions thrown. You can also use AsReadOnly() provided by List<T> to have the same effect.
In order to return a read only view of the list, we need to create a new instance of ReadOnlyCollection<Studentgt;. This would make sure that any external update can be avoided on the collection. In order to do fulfill a similar requirement in .net framework 4.5, we just need to use IReadOnlyCollection based return type as the return type of the method. Although the user of this method can cast it to the generic List type and update the list, but the intent of the method is very clear that it is just returned for consumption. But there would be no exceptions for such operations.
Basically List<T> is provided with an updated definition in .net framework 4.5. It implements some additional interfaces. One of them is IReadOnlyCollection<T>. Is this semantically correct to implement such interfaces when the the type allows adding and removing items? Don't even worry about this is Implementation we are talking about, not inheritance. Implementing an interface just means the "Can Do" for a type. Let's not confuse the interface implementation with inheritance. List<T> can be used in all places where a reference of interface type is used including method parameters and return type. Hence Liskov's Substitution Principle still holds true.
Here Student is a simple class with two properties StudentId and StudentName. The class exposes observational immutability. Here the definition of Student can be as follows:
Other Related Interfaces
In the above discussion, we can notice that List<T> also implements IReadOnlyList<T> . Basically .net framework 4.5 also includes some other interfaces including IReadOnlyList<T> and IReadOnlyDictionary<TKey, TValue>. Here the former provides an index support to IReadOnlyCollection<T> and latter can be used to provide a read only view of the dictionary.
You can verify that the definition of Dictionary<T> has also been updated to support IReadOnlyDictionary<TKey, TValue>.
Covariance & New Interface Types
IReadOnlyCollection and IReadOnlyList are covariant collections. As you might remember the feature of covariance and contravariance was introduced in .net framework 4.0. As we know that a type's instance can be assigned to the reference of its base type or interface type based on Polymorphism. Covariance allows a collection of child class to be assigned to a collection of base type. This is defined with out keyword with generic parameter.
In the above code, GetStudents() is supposed to return a collection of Student. But it returns one for GraduateStudent. Here GraduateStudent is a sub-type of Student. This is specially useful for API implementation where a sub-type needs to return the collection of child type of the type argument. This generally comes as a surprise while implementing child classes. The definition of GraduateStudent can be as follows: