Making Immutable Object Graphs Easier in C#

| by Jonathan Allen Follow 396 Followers on May 10, 2013. Estimated reading time: 2 minutes |

A note to our readers: You asked so we have developed a set of features that allow you to reduce the noise: you can get email and web notifications for topics you are interested in. Learn more about our new features.

Creating a simple immutable class in C# is easy. You just need to create a constructor and fail to create public setters. But often that’s not enough. Eventually you may want to create deep graphs that, for efficiencies sake, should be created via a builder. Or perhaps you want to make non-destructive updates by creating methods that return a copy of the object with one field changed (e.g. the AddMinutes method on DateTime). Building out all these builders and methods can be quite tedious and thus error prone.

Andrew L Arnott has a solution that relies on T4 based code generators. T4, if you aren’t familiar with it, stands for Text Template Transformation Toolkit. This is at the core of Visual Studio’s code generation capabilities and libraries such as Entity Framework rely on it. The T4 scripts take a mutable class and create an immutable clone.

Andrew’s toolkit makes a somewhat controversial decision to not emit public constructors. Instead you are expected to use a static Create method or start with the Default instance and modify it from there. This is done using the WithXxx methods, for which there is one per property.

We can make a couple more enhancements though. For classes with many properties, if you need to change several properties at once, allocating a new object with each property change as an intermediate step is wasteful and can contribute to GC pressure. So we also add a With method that takes optional parameters for every property found on the class, allowing bulk property changes. Finally, for scenarios where you have several changes to make to the object but wish to do so in a multistep fashion (or just prefer property setters to With- method calls), we can construct a Builder class that allows mutation, and then can return the immutable copy when you’re done. This pattern is very similar to String and StringBuilder in the .NET Framework, and also like the recent immutable collections mentioned earlier.

Of course if you don’t like these decisions you can easily modify the T4 templates. Andrew intentionally broke up the templates into smaller file to make this easier. You can also add your own extensions without significantly changing the base templates.

Like all well written code generators, this one heavily uses partial methods. Partial methods allow developers to inject additional logic into code-generated methods without having to modify the generated file. For example, one can implement a method to set partial default values for the immutable object. Partial methods that aren’t implemented will be automatically stripped out by the compiler, thus incurring no runtime cost.

You can read more about Arron’s experiments with Immutable Object Graphs on his blog.

Rate this Article

Adoption Stage

Hello stranger!

You need to Register an InfoQ account or or login to post comments. But there's so much more behind being registered.

Get the most out of the InfoQ experience.

Tell us what you think

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Another possibility is to use F# 'record' types by Faisal Waris

Not sure about the entire use case here but F# has record types which seem to fit the bill quite well.

Consider two record types A and B, where B uses A, defined as follows:

type A = {Data:string}
type B = {Name:string ; A:A }

Define an instance of B (somewhat like JSON):

let b = {Name="b"; A={Data="a data"}}

Here b is immutable.

Lets say we want to 'update' the Name of b and return a new instance.

let b2 = {b with Name="b2"}

So creating a new immutable instance type B is as simple as taking an existing instance (prototype) and 'overriding' one or more fields.

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

Allowed html: a,b,br,blockquote,i,li,pre,u,ul,p

Email me replies to any of my messages in this thread

1 Discuss

Login to InfoQ to interact with what matters most to you.

Recover your password...


Follow your favorite topics and editors

Quick overview of most important highlights in the industry and on the site.


More signal, less noise

Build your own feed by choosing topics you want to read about and editors you want to hear from.


Stay up-to-date

Set up your notifications and don't miss out on content that matters to you