Reputation: 14513
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:
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;
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
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
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
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
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
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
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
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
Reputation: 1359
Upvotes: 2