.Net Tips – making a serializable immutable struct

Check out my new course Learn you some Lambda best practice for great good! and learn the best practices for performance, cost, security, resilience, observability and scalability.

As you might know already, an object is immutable if its state doesn’t change once it has been created.

In C# the most used immutable type is string, this means every time you modify the value of a string variable you are actually creating a new string object and updating the reference of the variable to point to the new object.

Class vs Struct

When creating a new type, you have the choice of either a class or a struct. The general rule of thumb is to go with a class except for lightweight types smaller than 16 bytes in which case it is more efficient to use a struct. The reason a struct can be more efficient is because a struct is a value type and therefore goes straight onto the stack so we don’t have the overhead of having to hold the reference to the object itself (4 bytes in a 32bit system).

Mutable vs Immutable

In addition, you also have to consider whether your type should be mutable or immutable. In general, a struct should always be immutable because a struct usually represents some fundamental value – such as the number 5 – and whilst you can change a variable’s value you don’t logically change the value itself.

Also, data loss is far too easy with mutable structs, consider the following:

Foo foo = new Foo(); // a mutable struct
foo.Bar = 27;
Foo foo2 = foo;
foo2.Bar = 55;

Now foo.Bar and foo2.Bar is different, which is often unexpected.

Here are some of the advantages of using an immutable value type:

  • Easier validation – if you validate the parameters used to construct your object, your object will never be invalid as its state can never be changed.
  • Thread safety – immutable types are inherently thread-safe because there is no chance for different threads to see inconsistent views of the same data if the data can never be changed.
  • Better encapsulation – immutable types can be exported from your objects safely because the caller cannot modify the internal state of your objects.
  • Better for hash-based collections – the value returned by Object.GetHashCode() must be an instance invariant, which is always true for immutable types.

Deserializing an Immutable Struct

To create an immutable struct, you usually have no setters on properties and in all likelihood the private variables that the getters return will be made readonly too to enforce the write-once rule. The lack of public setters on properties, however, represents a challenge when serializing/deserializing the immutable structs.

The easiest way to get around this in my experience is to simply implement the ISerializable interface and providing a constructor which takes a SerializationInfo and a StreamingContext object:

public struct MyStruct: ISerializable
    private readonly int _x;
    private readonly int _y;

    // normal constructor
    public MyStruct(int x, int y) : this()
        _x = x;
        _y = y;

    // this constructor is used for deserialization
    public MyStruct(SerializationInfo info, StreamingContext text) : this()
        _x = info.GetInt32("X");
        _y = info.GetInt32("Y");

    public int X { get { return _x; } }
    public int Y { get { return _y; } }

    // this method is called during serialization
    [SecurityPermission(SecurityAction.Demand, SerializationFormatter = true)]
    public void GetObjectData(SerializationInfo info, StreamingContext context)
        info.AddValue("X", X);
        info.AddValue("Z", Y);


StackOverflow thread on immutability of structs

Patrick Smacchia’s article on Immutable Types: understand their benefits and use them

Eric Lippert‘s series on immutability in C#:

Immutability in C# Part One: Kinds of Immutability

Immutability in C# Part Two: A Simple Immutable Stack

Immutability in C# Part Three: A Covariant Immutable Stack

Immutability in C# Part Four: An Immutable Queue

Immutability in C# Part Five: LOLZ!

Immutability in C# Part Six: A Simple Binary Tree

Immutability in C# Part Seven: More on Binary Trees

Immutability in C# Part Eight: Even More On Binary Trees

Immutability in C# Part Nine: Academic? Plus my AVL tree implementation

Immutability in C# Part Ten: A double-ended queue

Immutability in C# Part Eleven: A working double-ended queue

Luca Bolognese‘s series on implementing immutable value objects:

Creating an immutable value object in C# – Part I – Using a class

Creating an immutable value object in C# – Part II – Making the class better

Creating an immutable value object in C# – Part III – Using a struct

Creating an immutable value object in C# – Part IV – A class with a special value

Creating an immutable value object in C# – Part V – Using a library

Liked this article? Support me on Patreon and get direct help from me via a private Slack channel or 1-2-1 mentoring.
Subscribe to my newsletter

Hi, I’m Yan. I’m an AWS Serverless Hero and the author of Production-Ready Serverless.

I specialise in rapidly transitioning teams to serverless and building production-ready services on AWS.

Are you struggling with serverless or need guidance on best practices? Do you want someone to review your architecture and help you avoid costly mistakes down the line? Whatever the case, I’m here to help.

Hire me.

Check out my new podcast Real-World Serverless where I talk with engineers who are building amazing things with serverless technologies and discuss the real-world use cases and challenges they face. If you’re interested in what people are actually doing with serverless and what it’s really like to be working with serverless day-to-day, then this is the podcast for you.

Check out my new course, Learn you some Lambda best practice for great good! In this course, you will learn best practices for working with AWS Lambda in terms of performance, cost, security, scalability, resilience and observability. We will also cover latest features from re:Invent 2019 such as Provisioned Concurrency and Lambda Destinations. Enrol now and start learning!

Check out my video course, Complete Guide to AWS Step Functions. In this course, we’ll cover everything you need to know to use AWS Step Functions service effectively. There is something for everyone from beginners to more advanced users looking for design patterns and best practices. Enrol now and start learning!

Are you working with Serverless and looking for expert training to level-up your skills? Or are you looking for a solid foundation to start from? Look no further, register for my Production-Ready Serverless workshop to learn how to build production-grade Serverless applications!

Find a workshop near you