Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IReadOnlyCollection vs ReadOnlyCollection

Tags:

c#

.net

linq

There are a couple of similar questions already on SO, but none of the ones I found really touches on this particular topic, so here it goes...

My understanding is that one should always attempt to return an interface over a concrete class. Won't go into the reasons behind it, plenty of things on SO about that already.

However in the case of an IReadOnlyCollection vs a ReadOnlyCollection I'm not sure if that rule should be followed.

An IReadOnlyCollection can be easily cast into a List, which... well... breaks the ReadOnly aspect that the contract promises.

ReadOnlyCollection however cannot be cast into a List, but it means returning a concrete class.

In the long run, does it actually matter? It seems to me like in most cases a ReadOnly*/IReadOnly* object is only returned returned by either a method or a read-only property.

So even if the user decides to cast it to something else (in the case of a IReadOnly* object) or use LINQ to create a collection of some kind out of it (in the case of ReadOnly* object), there's really no way that the class exposing the ReadOnly*/IReadOnly* object is going to accept that back.

So what's the recommendation here, return an IReadOnly* interface or a concrete ReadOnly* class instance?

like image 910
cogumel0 Avatar asked Jul 18 '17 10:07

cogumel0


People also ask

What is the use of ReadOnlyCollection in C#?

An instance of the ReadOnlyCollection<T> 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.

Is IReadOnlyList immutable?

It demonstrates that IReadOnlyList<T> can change even during duration of a single method! Remember not to use ReadOnlyCollection<T> class to create a defensive copy. This class is only a wrapper - it does not copy the actual data. These types are truly immutable, they never change their contents after they are created.


1 Answers

IReadOnlyCollection<T> can only be cast to List<T> if the underlying object is of that type. ReadOnlyCollection<T> for example also implements IReadOnlyCollection<T>.

So my recommendation, return IReadOnlyCollection<T> and if you are worried that caller would wrongly cast it to something it shouldn't, make sure the underlying type is ReadOnlyCollection<T>

public IReadOnlyCollection<User> GetUsers()
{
   return new ReadOnlyCollection<User>();
}


But returning IReadOnlyCollection<T> should be enough for caller of function to understand it is supposed to be read only.
Note that you can never completely secure your code with a ReadOnlyCollection<T>, caller can still use reflection to access the internal list and manipulate it.
The only option in that case would be to create a copy if the list and return that.

like image 163
Magnus Avatar answered Sep 19 '22 17:09

Magnus