Monday, May 13, 2013

Mutable-Immutable Data Transfer Objects in C#

The getters and setters in C# can make implementing POCOs easy. But sometimes when you are writing an API you need an object that can be modified internally but is read-only externally. In my mind, it is ideally better to have both objects strongly related to each other because if you remove one field or property in one, then it is removed for the other.

So how is this done?

You can't do this:
    public class ImmutableThing
    {
        int Id { get; }
        string Name { get; }
    }

    public class MutableThing : ImmutableThing 
    {
        int Id { get; set; }
        string Name { get; set; }
    }

Because the compiler will complain. "Automatically implemented properties must define both get and set accessors." Having the Immutable object extend the Mutable object yields the same result. 

To solve this, an Interface must be defined:

    public interface IThing
    {
        int Id { get; }
        string Name { get; }
    }

Now have the Immutable object extend from the interface:

    public class ImmutableThing : IThing
    {
        private int id = 0;
        private string name = null;
        public ImmutableThing(int id, string name)
        {
            this.id = id;
            this.name = name;
        }
        public int Id { get { return id; } }
        public string Name { get { return name; } }
    }

And the Mutable interface:
    public class MutableThing : IThing
    {
        public int Id { get; set; }
        public string Name { get; set; }
    }

You can have the fields in an abstract class so that you can have methods available for both immutable and mutable objects:
     public abstract class AbstractThing
    {
        protected int id = 0;
        protected string name = null;
    }

    public class ImmutableThing : AbstractThing, IThing

    {
        public ImmutableThing(int id, string name)
        {
            base.id = id;
            base.name = name;
        }
        public int Id { get { return id; } }
        public string Name { get { return name; } }
    }

    public class MutableThing : AbstractThing, IThing

    {
        public int Id 
        { 
            get { return id; }
            set { base.id = value; }
        }
        public string Name 
        { 
            get { return name; }
            set { base.name = value; }
        }
    }

I wish Visual Studio 2012 can tell me right away if it won't compile. I currently have to rebuild it each time.