Wednesday, September 9, 2015

ReadOnlyCollection<T> in C#, Is It Really Read Only?

With .NET 2.0 ReadOnlyCollection<T>  was introduced and I have seen this question “Is ReadOnlyCollection<T> really read only?”. Well the simple answer is, it is, but you need to understand how this works and otherwise you will be surprised with some results. In this post, let’s see how  ReadOnlyCollection<T> works.

For example, let’s take following List of type string.
List<string> strings = new List<string>()
    "Visual Studio 2010","Visual Studio 2012","Visual Studio 2013"
So basically there is two ways that I can create a ReadOnlyCollection<T> from this.
ReadOnlyCollection<string> readOnlyStrings = strings.AsReadOnly();
// or
ReadOnlyCollection<string> readOnlyStrings = new ReadOnlyCollection<string>(strings);
One from calling List<T>.AsReadOnly() method which will return a ReadOnlyCollection<T> or by calling the constructor of ReadOnlyCollection<T>. Both of this will achieve the same.

Now if you try to modify the readOnlyStrings collection, you can’t. Because it is read only. But what about modifying strings collection which is of type List<T>. Well you should be able to modify it for example by adding a new item.
strings.Add("Visual Studio 2015");
Now let’s see what do we have on the readOnlyStrings collection.
foreach (string item in readOnlyStrings)
Surprisingly you will see that your readOnlyStrings collection has been modified. But did you add an item to readOnlyStrings, No, but you did add an item to strings.

So what happened here is nicely described on MSDN.

“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.”

Now let’s take another scenario.

Here I have a simple class named VisualStudio and there I have a helper method which will return new instance of List<VisualStudio>.
class VisualStudio
    public string Version { get; set; }
    public static List<VisualStudio> GetVisualStudios()
        return new List<VisualStudio>()
            new VisualStudio() { Version = "Visual Studio 2010" },
            new VisualStudio() { Version = "Visual Studio 2012" },
            new VisualStudio() { Version = "Visual Studio 2013" },
Now I have the following ReadOnlyCollection<T> where T is VisualStudio.
ReadOnlyCollection<VisualStudio> readOnlyVisualStudios = new ReadOnlyCollection<VisualStudio>(VisualStudio.GetVisualStudios());
Now let’s try to modify an item in the readOnlyVisualStudios and see the content of readOnlyVisualStudios.
readOnlyVisualStudios[0].Name = "Microsoft Visual Studio 2010";
foreach (VisualStudio item in readOnlyVisualStudios)
Again it seems readOnlyVisualStudios has been modified. This shows another feature of ReadOnlyCollection<T>. That is when the T in ReadOnlyCollection<T> is a complex type, the individual items of ReadOnlyCollection<T> can be modified either by changing the values of it’s properties or by calling the methods of complex type. But the following is illegal and will throw an error.
readOnlyVisualStudios[0] = null;
// or
readOnlyVisualStudios[0] = new VisualStudio() { Name = "Microsoft Visual Studio 2010" };

So that’s it.  Keep in mind that when working with ReadOnlyCollection<T>, you need to make sure, you are not letting the underline collection to be modified or only let the class that contains the underline collection to modify  it and not others for instance like below.
private List<string> strings;
public ReadOnlyCollection<string> Strings
    get { return new ReadOnlyCollection<string>(strings); }
If you want your strings which is of List<T> to be read only, make it private so you (containing class) can do what ever you want and expose as a public ReadOnlyCollection<T> to consumers.

Hope this helps.

Happy Coding.


No comments:

Post a Comment