Reputation: 9185
I am working on creating an immutable class.
I have marked all the properties as read-only.
I have a list of items in the class.
Although if the property is read-only the list can be modified.
Exposing the IEnumerable of the list makes it immutable.
I wanted to know what is the basic rules one has to follow to make a class immutable ?
Upvotes: 129
Views: 66551
Reputation: 8017
All you need is L... Ehm record
and C# 9.0 or newer.
public record Customer(string FirstName, string LastName, IEnumerable<string> Items);
//...
var person = new Customer("Test", "test", new List<string>() { "Test1", "Test2", "Test3" });
// you can't change anything within person variable
// person.FirstName = "NewName";
This gets translated into immutable class called Customer with three properties, FirstName
, LastName
and Items
.
If you need an immutable (a read-only) collection as a property of the class, it is better to expose it as IEnumerable<T>
or ReadOnlyCollection<T>
than something from System.Collections.Immutable
Upvotes: 9
Reputation: 361
The original question and answer date from the end of 2008, there is now a System.Collections.Immutable namespace that I believe dates from the earliest .NET Core (1.0) . The namespace is still not available in .NET Standard (current version 2.1) and .NET framework (current version 4.8). This namespace has lots of immutable collections including the ImmutableList, which is asked about in the original question. However, I believe the System.Collections.Immutable namespace may appear in .NET 5 which is at release candidate 2 at the moment.
Also, starting with C# 6 you can have immutable auto-implemented properties using just { get; } .
Upvotes: 1
Reputation: 38842
Use the ReadOnlyCollection
class. It's situated in the System.Collections.ObjectModel
namespace.
On anything that returns your list (or in the constructor), set the list as a read-only collection.
using System.Collections.ObjectModel;
...
public MyClass(..., List<ListItemType> theList, ...)
{
...
this.myListItemCollection= theList.AsReadOnly();
...
}
public ReadOnlyCollection<ListItemType> ListItems
{
get { return this.myListItemCollection; }
}
Upvotes: 5
Reputation: 12009
Another option would be to use a visitor pattern instead of exposing any internal collections at all.
Upvotes: 2
Reputation: 241790
I think you're on the right track -
Upvotes: 132
Reputation: 25052
Also, keep in mind that:
public readonly object[] MyObjects;
is not immutable even if it's marked with readonly keyword. You can still change individual array references/values by index accessor.
Upvotes: 12
Reputation: 124696
To be immutable, all your properties and fields should be readonly. And the items in any list should themselves be immutable.
You can make a readonly list property as follows:
public class MyClass
{
public MyClass(..., IList<MyType> items)
{
...
_myReadOnlyList = new List<MyType>(items).AsReadOnly();
}
public IList<MyType> MyReadOnlyList
{
get { return _myReadOnlyList; }
}
private IList<MyType> _myReadOnlyList
}
Upvotes: 21