tom
tom

Reputation: 14513

What does immutable and readonly mean in C#?

Is it correct that it is not possible to change the value of an immutable object?

I have two scenarios regarding readonly that I want to understand:

  1. What if I have a collection and mark it as readonly, like the following. Can I still call _items.Add?

    private readonly ICollection<MyItem> _items;
    
  2. And also for the following variable, if later on I call _metadata.Change which will change the internal values of a couple member variable in the Metadata instance. Is _metadata still immutable?

    private readonly Metadata _metadata;
    

For both variables above, I totally understand that I can't directly assign new values to them outside of initializer and constructors.

Upvotes: 17

Views: 16766

Answers (8)

Assil
Assil

Reputation: 690

In languages like C++ there are quite a few different uses of the keyword "const", it is partly easy for developers to pass constant parameters and also constant pointers of constant values.

That is not easy in C#. We need to build immutable class by definition, which means Once an instance is created, there is no way it can be changed programmatically.

Java has a little easier way than C# because of the keyword final and its usages.

Lets consider this example and see how immutable it is..

public sealed class ImmutableFoo
    {
        private ImmutableFoo()
        {

        }

        public string SomeValue { get; private set; }
        //more properties go here

        public sealed class Builder
        {
            private readonly ImmutableFoo _instanceFoo = new ImmutableFoo();
            public Builder SetSomeValue(string someValue)
            {
                _instanceFoo.SomeValue = someValue;
                return this;
            }

            /// Set more properties go here
            /// 

            public ImmutableFoo Build()
            {
                return _instanceFoo;
            }
        }
    }

You can use it like this

public class Program
    {
        public static void Main(string[] args)
        {
            ImmutableFoo foo = new ImmutableFoo.Builder()
                .SetSomeValue("Assil is my name")
                .Build();

            Console.WriteLine(foo.SomeValue);
            Console.WriteLine("Hit enter to terminate");
            Console.ReadLine();
        }
    }

Upvotes: 0

NOtherDev
NOtherDev

Reputation: 9672

I suggest you to read the series of blog posts by Eric Lippert. The first part is Immutability in C# Part One: Kinds of Immutability. Very informative and helpful, as always. The series describes what does it mean for a variable to be readonly, immutable etc. in details.

Generally, readonly means only that you can't re-assign a field outside the constructor. The field itself can be modified as long as it stays the same instance. So yes, you can add elements to the collection stored in readonly field.

About mutability, this is more complex and it depends a bit what kind of mutability you consider. When Metadata internal values are references and those references itself (the instances it point to) doesn't change, you could say Metadata stays not mutated. But it is mutated logically. See Eric's posts for more insights.

Upvotes: 26

Anders Abel
Anders Abel

Reputation: 69260

An immutable object is one that cannot be changed, once created. In C# strings are immutable. If you look at the string manipulation routines you can see that all of them return a new, modified, string and leaves the original string unchanged.

This facilitates the string handling considerably. When you have a reference to a string, you can be sure that noone else will unexpectedly change it under your feet.

readonly is something else. It means that the reference cannot be changed, once set and that it can only be set during object construction. In your examples you can change the contents of _items or the properties of _metadata, but you cannot assign another ICollection<MyItem> to the _items member or another Metadata instance to _metadata.

readonly is set on the reference to an object. Immutability is a property of the object itself. These can be freely combined. To make sure that a property is not changed in any way, it should be a readonly reference to an immutable object.

Upvotes: 9

IAbstract
IAbstract

Reputation: 19881

private readonly ICollection<MyItem> _items;

Does not prevent items from being added. This simply prevents _items from being re-assigned. The same is true for _metadata. Accessible members of _metadata can be changed - _metadata cannot be re-assigned.

Upvotes: 3

viniciushana
viniciushana

Reputation: 245

The readonly keyword applies to a variable - this means you can't assign another value to it, but you can alter its internal state. That's why you can alter a collection's items but you can't assign a new collection to the variable.

Upvotes: 2

Greg
Greg

Reputation: 23463

There is nothing preventing you from mutating an object stored in a readonly field. So you CAN call _items.Add() and metadata._Change() outside the constructor/initializer. readonly only prevents you from assigning new values to those fields after construction.

Upvotes: 4

Shaun Hamman
Shaun Hamman

Reputation: 2347

Marking a field as read-only only means that you cannot change the value of that field. It has no bearing on the internal state of the object there. In your examples, while you would not be able to assign a new metadata object to the _metadata field, nor a new ICollection to the _items field (outside of a constructor that is), you can change the internal values of the existing objects stored in those fields.

Upvotes: 7

tonyjy
tonyjy

Reputation: 1359

  1. Yes.
  2. Readonly doesn't equal to immutable. You can still call _metadata.Change.

Upvotes: 2

Related Questions