Discriminated Unions for Designing Domain Models in C#

Giorgi Koguashvili
2 min readAug 1, 2017

Domain model requires thorough designing in which are well suited ATD (Algebraic Data Type) such as Sum Types, which name in computer science is Discriminated Unions.

Image taken from Bartosz Milewski’s blog

Consider a simple example to make it more clear.

Imagine we have Contact class:

These are all defined as simple strings, but really are they just strings? Of course not. The Name can consist of First Name and Last Name. Or is an Email just a set of symbols? I know that at least it should contain @ and it is necessarily.

Let’s improve us domain model:

In this classes will be validations during creating and we will eventually have valid models. Consturctor in PersonaName class require FirstName and LastName at the same time. This means that after the creation, it can not have invalid state.

And Contact class respectively:

In this case we have same problem, object of Contact class may be in invalid state. I mean it may have EmailAddress but haven’t Name:

Let’s fix it and create Contact class with constructor which requires PersonalName, EmailAddress and PostalAddress:

But here we have another problem. What if Person have only EmailAdress and haven’t PostalAddress?

If we think about it there we realize that there are three possibilities of valid state of Contact class object:

  1. A contact only has an email address
  2. A contact only has a postal address
  3. A contact has both an email address and a postal address

Let’s write out domain models. For the beginning we will create Contact Info class which state will be corresponding with above cases.

And Contact class:

Let’s try use it:

Let’s add Match method in ContactInfo class:

In the match method, we can write this code, because the state of the contact class is controlled with constructors and it may have only one of the possible states.

Let’s create an auxiliary class, so that each time do not write as many code:

We can have such a class in advance for several types, as is done with delegates Func, Action. 4–6 generic type parameters will be in full for Union class.

Let’s rewrite ContactInfo class:

Here the compiler will ask override for at least one constructor. If we forget to override the rest of the constructors we can’t create object of ContactInfo class with another state. This will protect us from runtime exceptions during Matching.

That’s all. I hope you enjoyed.

Example taken from the site F# for fun and profit.

--

--