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

23,320

Solution 1

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.

Solution 2

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.

Share:
23,320

Related videos on Youtube

tymtam
Author by

tymtam

https://www.linkedin.com/in/tymekm/ https://github.com/tymtam2

Updated on January 26, 2020

Comments

  • tymtam
    tymtam over 4 years

    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.

    • Kieren Johnstone
      Kieren Johnstone almost 11 years
      I prefer .ToArray(). Simpler IMO!
    • Uwe Keim
      Uwe Keim over 6 years
      @KierenJohnstone probably slower, too.
    • bboyle1234
      bboyle1234 over 4 years
      .ToArray() creates an entirely new array so it's slower, and the array is mutable, meaning, any of its elements can be changed. .AsReadOnly() is faster, and consumers can't mutate it by changing individual elements. It does change when the original list is changed though.
  • tymtam
    tymtam almost 11 years
    But I can cast back AsReadOnly().Items, can't I?
  • dlev
    dlev almost 11 years
    @Tymek You cannot: AsReadOnly() creates a new, non-List<T> class, which has no public methods that permit mutation of the underlying list. (Items is protected, so random consumers can't access it.)
  • Steven
    Steven almost 11 years
    Items is not the original list, you can't change the original list.
  • tymtam
    tymtam almost 11 years
    @Steven Items is the original list, but I only now noticed that it's protected. Doh!
  • Steven
    Steven almost 11 years
    Also note that the List<T>.AsReadOnly() method exists since .NET 2.0 while the IReadOnlyCollection interface is new in .NET 4.5. So the API might overlap a bit here, but AsReadOnly is still useful.
  • Steven
    Steven almost 11 years
    @Tymek, the original list? Interesting. I didn't know that.
  • nawfal
    nawfal over 10 years
    @Steven yes, AsReadonly always returned ReadonlyCollection<T> since .NET 2.0, just that ReadonlyCollection<T> implemented IReadonlyCollection<T> recently.