Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

List<T>.AsReadOnly() vs IReadOnlyCollection<T>

List<T> implements IReadOnlyCollection<T> interface and provides the AsReadOnly() method which returns ReadOnlyCollection<T> (which in turn implements IReadOnlyCollection<T>).

What is the usage/reason for AsReadyOnly()? Its existence smells of one or two edge cases where just returning the list as IReadOnlyCollection<T> is just not good enough.

At first I though it may be to prevent casting the cost-ness away but it looks like you can do that with ReadOnlyCollection<T>'s Items accessor.

BTW. The documentation for ReadOnlyCollection<T> type reads

Provides the base class for a generic read-only collection.

which, in my head, conflicts with having a constructor described as

Initializes a new instance of the (...) class that is a read-only wrapper around the specified list.

Update: I did not see that ReadOnlyCollection<T>'s Items is protected.

like image 819
tymtam Avatar asked Jul 01 '13 06:07

tymtam


People also ask

What is IReadOnlyCollection?

The IReadOnlyCollection interface extends the IEnumerable interface and represents a basic read-only collection interface. It also includes a Count property apart from the IEnumerable members as shown in the code snippet given below.

What is IReadOnlyList in c#?

Represents a read-only collection of elements that can be accessed by index.

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.

Can you add to a readonly list C#?

In C# there is the readonly keyword that enforced the rule that the variable must be initialised as it's declared or in the constructor. This works as expected for simple types, but for objects and lists it's not quite like that. With a list, you can still add, remove and change items in the list.


2 Answers

If you just return an actual List<T> as an IReadOnlyList<T>, then the caller can always just cast it back, and then modify the list as they please. Conversely, calling AsReadOnly() creates a read-only wrapper of the list, which consumers can't update.

Note that the read-only wrapper will reflect changes made to the underlying list, so code with access to the original list can still update it with the knowledge that any consumers of the read-only version will see those changes.

like image 57
dlev Avatar answered Sep 18 '22 06:09

dlev


First of all it's not that AsReadOnly() was added because IReadOnlyList<T> isn't good enough -- IReadOnlyList<T> is only available starting with .NET 4.5 while AsReadOnly() method exists since .NET 2.

More importantly: AsReadOnly() and IReadOnlyList<T> serve very different purposes.

ReadOnlyCollection<T> is meant for implementing object models, for example things like Dictionary<K,V>.Keys and Dictionary<K,V>.Values. This is for scenarios where consumers shouldn't be able to change the contents while the producer can. It works in tandem with Collection<T> which provides hooks for the owner to validate changes or perform side effects when items get added.

IReadOnlyList<T> on the other hand is simply an interface that provides a read-only view of the collection. Methods can use it in order to say "I need a random access collection but I don't need to be able to modify it". For example, a BinarySearch method might look like this:

public int BinarySearch<T>(IReadOnlyList<T> list, int start, int length);

In order to make this method useful, it's required to be able to pass in any List. Forcing to create wrapper collections would be prohibitively expensive.

like image 30
Immo Landwerth Avatar answered Sep 21 '22 06:09

Immo Landwerth