Search code examples
c#readonly-collectionimmutable-collections

ReadonlyCollection, are the objects immutable?


I'm trying using ReadOnlyCollection to make object immutable, I want the property of object are immutable.

public ReadOnlyCollection<FooObject> MyReadOnlyList
{
    get
    {
        return new ReadOnlyCollection<FooObject>(_myDataList);
    }
}

But I little confused.

I tried to change the property of the object in to MyReadOnlyList using a foreach and ... I can change value property, is it correct? I understood ReadOnlyCollection set an add level to make the object immutable.


Solution

  • The fact that ReadOnlyCollection is immutable means that the collection cannot be modified, i.e. no objects can be added or removed from the collection. This does not mean that the objects it contains immutable.

    This article by Eric Lippert, explains how different kinds of immutability work. Basically, a ReadOnlyCollection is an immutable facade which can read the underlying collection (_myDataList), but cannot modify it. However, you can still change the underlying collection since you have a reference to _myDataList by doing something like _myDataList[0] = null.

    Furthermore, the objects returned by ReadOnlyCollection are the same ones returned by _myDataList, i.e. this._myDataList.First() == this.MyReadOnlyList.First() (with LINQ). This means that if an object in _myDataList is mutable, then so is the object in MyReadOnlyList.

    If you want the objects to be immutable, you should design them accordingly. For instance, you might use:

    public struct Point
    {
        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }
    
        // In C#6, the "private set;" can be removed
        public int X { get; private set; }
        public int Y { get; private set; }
    }
    

    instead of:

    public struct Point
    {
        public int X { get; set; }
        public int Y { get; set; }
    }
    

    Edit: in this case, as noted by Ian Goldby, neither struct allows you to modify properties of the elements in the collection. This happens because structs are value types and when you access an element the collection returns a copy of the value. You can only modify the properties of a Point type if it is a class, which would mean that references to the actual objects are returned, instead of copies of their values.