Thursday, 24 August 2017

Immutable objects in C#

What are Immutable Objects?

Immutable objects are objects which once loaded cannot be changed / modified by any way external or internal.

Where are Immutable Objects Used?

If I put it in one line, Immutable objects are used for data WHICH IS STATIC. Below are some of the instances of the same.
  • Master data: One of the biggest uses of immutable objects is to load master data. Master data like country, currency, region, etc. rarely change. So we would like to load master data once in the memory and then we do not want it to be modified.
  • Configuration data: All application needs configuration data. In the Microsoft world, we normally store these configuration data into Web.config or App.config file. Such kind of data is represented by objects and these data once loaded in the application memory will not change. It's again a good practice to make these kind of configuration data objects as immutable.
  • Singleton objects: In applications, we normally create singleton objects for shared static data. So if the shared data is not changing, it’s an awesome candidate for immutable objects. In case you are new to Singleton pattern, please refer to this article Singleton Pattern in C#.

How Can We Create Immutable Objects in C#?

Immutable objects can be created only from immutable classes. To create an immutable class is a three step process:
Step 1: Remove the setters of the class, only have getters.
The first step towards creating an immutable class is to remove the setters. As we said, values of a immutable class cannot be modified EXTERNALLY or INTERNALLY. So by removing the getters, any client who creates the object of this class cannot modify the data once loaded.
class Currency
{
        private string _CurrencyName;
        public string CurrencyName
        {
            get { return _CurrencyName; }
        }
        private string _CountryName;
        public string CountryName
        {
            get { return _CountryName; }
        }        
}
Step 2: Provide parameters via constructor.
We have removed the getters so there is no way to load data in to the class. So to provide data, we need to create constructors with parameters via which we can pass data to the object. Below is the modified code for the same.
class Currency
{
// property Code removed for clarity

        public Currency(string paramCurrencyName,
                        string paramCountryName)
        {
            _CurrencyName = paramCurrencyName;
            _CountryName = paramCountryName;
        }
}
Step 3: Make the variables of the property READONLY
As we said in the previous definition, immutable objects cannot be modified by ANY WAY once the data is loaded. I will go one step further and say it cannot be modified EXTERNALLY by client or INTERNALLY by the class code himself.
But if you see our currency class, the variables can be modified after the object creation. In other words, see the below class code. We have created a method in the class called as “SomeLogic”. This method is able to successfully modify the variables after the object has been created.
class Currency
{
        private string _CountryName;

        public string CountryName
        {
            get { return _CountryName; }
        }

        public void SomeLogic()
        {
            _CountryName = "I can not change this";
        }
}
So the solution for the above to make the variables “READONLY”. Below is the currency class modified where the property variables are made readonlyReadonly variables can be only initialized in the constructor and later they cannot be modified.
class Currency
    {
        private readonly string _CurrencyName;

        public string CurrencyName
        {
            get { return _CurrencyName; }
        }
        private readonly string _CountryName;

        public string CountryName
        {
            get { return _CountryName; }
        }
        public Currency(string paramCurrencyName,
                        string paramCountryName)
        {
            _CurrencyName = paramCurrencyName;
            _CountryName = paramCountryName;
        }
    }

No comments:

Post a Comment