.Net Tips – making a serializable immutable struct

You can become a serverless blackbelt. Enrol to my 4-week online workshop Production-Ready Serverless and gain hands-on experience building something from scratch using serverless technologies. At the end of the workshop, you should have a broader view of the challenges you will face as your serverless architecture matures and expands. You should also have a firm grasp on when serverless is a good fit for your system as well as common pitfalls you need to avoid. Sign up now and get 15% discount with the code yanprs15!

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:

[Serializable]
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);
    }
}

Reference:

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 I help companies go faster for less by adopting serverless technologies successfully.

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.


Skill up your serverless game with this hands-on workshop.

My 4-week Production-Ready Serverless online workshop is back!

This course takes you through building a production-ready serverless web application from testing, deployment, security, all the way through to observability. The motivation for this course is to give you hands-on experience building something with serverless technologies while giving you a broader view of the challenges you will face as the architecture matures and expands.

We will start at the basics and give you a firm introduction to Lambda and all the relevant concepts and service features (including the latest announcements in 2020). And then gradually ramping up and cover a wide array of topics such as API security, testing strategies, CI/CD, secret management, and operational best practices for monitoring and troubleshooting.

If you enrol now you can also get 15% OFF with the promo code “yanprs15”.

Enrol now and SAVE 15%.


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!