How to create immutable objects in C#?

delete picture delete · Feb 23, 2011 · Viewed 29.8k times · Source

In a question about Best practices for C# pattern validation, the highest voted answer says:

I tend to perform all of my validation in the constructor. This is a must because I almost always create immutable objects.

How exactly do you create an immutable object in C#? Do you just use the readonly keyword?

How exactly would this work if you want to validate in the constructor of your Entity Framework generated model class?

Would it look like below?

public partial readonly Person
{
    public Person()
}

Answer

Eric Lippert picture Eric Lippert · Feb 24, 2011

The interesting question here is your question from the comments:

What kind of object would you have that you do not need to modify the values at some point? I'm guessing not a model class, correct? I've had to change the name of a person in my database - this wouldn't fit with this idea.

Well, consider things that are already immutable. Numbers are immutable. Once you have the number 12, it's 12. You can't change it. If you have a variable that contains 12, you can change the contents of the variable to 13, but you are changing the variable, not the number 12.

Same with strings. "abc" is "abc", and it never changes. If you have a variable that contains "abc", you can change it to "abcd", but that doesn't change "abc", that changes the variable.

What about a list? {12, "abc"} is the list that is 12 followed by "abc", and that list never changes. The list {12, "abcd"} is a different list.

And that's where things go off the rails. Because in C# you can do it either way. You can say that there is referential identity between those two lists if lists are allowed to mutate their contents without changing their identity.

You hit the nail right on the head when you talk about the "model". Are you modeling something that changes? If so, then it is possibly wise to model it with a type that changes. The benefit of that is that the characteristics of the model match the system being modeled. The down side is that it becomes very tricky to do something like a "rollback" functionality, where you "undo" a change.

That is, if you mutate {12, "abc"} to {12, "abcd"} and then want to roll back the mutation, how do you do it? If the list is immutable you just keep around both values and choose which one you want to be the "current" value. If the list is mutable then you have to have the undo logic keep around an "undo function" which knows how to undo the mutation.

As for your specific example, you certainly can create an immutable database. How do you change the name of someone in your immutable database? You don't. You create a new database that has the data you want in it. The trick with immutable types is to do so efficiently, without copying billions of bytes. Immutable data structure design requires finding clever ways to share state between two nearly-identical structures.