How to obtain C# immutable object

In last article Writing immutable code in C# I touched reasons and benefits to writing code in immutable way. Today I would like to show you some possible implementations and their pros and cons.
Let me take previous example and describe my thoughts on the data object SupportCase.

public class SupportCase
{
    public string Title { get; set; }
    public Customer Customer { get; set; }
    public SupportCaseStatus Status { get; set; }
    public IList<string> Descriptions { get; set; }
}

This is implementation of Plain Old CLR Object (POCO) with both getters and setters. Following examples will try to declare the object immutable. I will focus on the object, but I will not focus on immutability of its properties (e.g. property Customer of the object SupportCase will be immutable – it will still point out to the same object Customer – but article does not solve immutability of object Customer or the list Descriptions).
Read-only class is probably the straight forward solution how to accomplish immutable object.

public class SupportCase
{
    public SupportCase(string title, Customer customer, SupportCaseStatus status, IList<string> descriptions)
    {
        Title = title;
        Customer = customer;
        Status = status;
        Descriptions = descriptions;
    }

    public string Title { get; private set; }
    public Customer Customer { get; private set; }
    public SupportCaseStatus Status { get; private set; }
    public IList<string> Descriptions { get; private set; }
}

Although the it may look good, we can use reflection as in previous example and change the state of object.

    ...
    PropertyInfo prop = sc.GetType().GetProperty("Title");
    MethodInfo setter = dynProperty.GetSetMethod(true);
    setter.Invoke(data, new object[] { "New Title" });
    ...

This situation can be fixed, by not defining setters at all. And if we will define default values for all parameters in constructor, we will get almost ideal solution.

public class SupportCase
{
    public SupportCase(string title, Customer customer, SupportCaseStatus status = SupportCaseStatus.New, IList<string> descriptions = null)
    {
        _title = title;
        _customer = customer;
        _status = status;
        _descriptions = descriptions;
    }

    private readonly string _title;
    public string Title { get { return _title; } }

    private readonly Customer _customer;
    public Customer Customer { get { return _customer; } }

    private readonly SupportCaseStatus _status;
    public SupportCaseStatus Status { get { return _status; } }

    private readonly IList<string> _descriptions;
    public IList<string> Descriptions { get { return _descriptions; } }
}

Such defined object is really immutable in C# from runtime perspective. It has only one disadvantage and it is constructor. If your object will grow to have tens of properties, the constructor will have same number of parameters. With default value for optional parameters and named arguments we can create and object in all combination.

    ...
    SupportCase sc1 = new SupportCase("Origin Title", cust);
    SupportCase sc2 = new SupportCase(title: "Origin Title", customer: cust, status: SupportCaseStatus.Open);
    SupportCase sc3 = new SupportCase
        (
            title: "Origin Title",
            customer: cust,
            descriptions: new List<string>(new string[] { "Description 1", "Description 2" })
        );
    ...

That’s all, now go write some code.

Leave a Reply

Your email address will not be published. Required fields are marked *