Create Value Object In C#

Problem

How to create a value object (pattern in Domain Driven Design) in C#?

Solution

Create a class that abstracts away (encapsulate) the ‘data’ in your domain and provide methods to work on it. Below is a class I don’t consider a good Value Object.

  1. public enum GenderType { Male, Female }  
  2.   
  3. public sealed class Gender1  
  4. {  
  5.     private readonly GenderType genderType;  
  6.   
  7.     internal Gender1(GenderType genderType)  
  8.     {  
  9.         this.genderType = genderType;  
  10.     }  
  11.   
  12.     public GenderType GenderType => this.genderType;  
  13. }  
  14.     [Fact]  
  15.     public void Setting_with_male_returns_Male_for_GenderType_prop()  
  16.     {  
  17.         var gender = new Gender1(GenderType.Male);  
  18.         Assert.Equal(  
  19.             expected: GenderType.Male,  
  20.             actual: gender.GenderType);  
  21.     }  

However, the class below is what I do consider a good Value Object.

  1. public sealed class Gender2  
  2. {  
  3.     private readonly GenderType genderType;  
  4.   
  5.     internal Gender2(GenderType genderType)  
  6.     {  
  7.         this.genderType = genderType;  
  8.     }  
  9.   
  10.     public bool IsMale => this.genderType == GenderType.Male;  
  11.     public bool IsFemale => this.genderType == GenderType.Female;  
  12. }  
  13.     [Fact]  
  14.     public void Setting_with_male_enum_returns_true_for_IsMale_prop()  
  15.     {  
  16.         var gender = new Gender2(GenderType.Male);  
  17.         Assert.True(gender.IsMale);  
  18.     }  

Discussion

The difference between the above two Gender classes is that the first one isn’t encapsulating its internal representation, i.e., how it holds the gender information in an enum.

Exposing the internal state as properties isn’t the same as encapsulating state, although this is a common misunderstanding. Good encapsulation is when the internals (data/behavior) are abstracted away from the client by providing domain-specific behavior.

The second Gender class does that by providing "IsMale" and "IsFemale" properties. This way, if the internal representation changes, say from enum to string, then the client doesn’t need to change/know.

  1. public sealed class Gender3  
  2. {  
  3.     private readonly string genderType;  
  4.   
  5.     internal Gender3(string genderType)  
  6.     {  
  7.         this.genderType = genderType;  
  8.     }  
  9.   
  10.     public bool IsMale =>  
  11.         this.genderType.ToUpper() == "MALE" || this.genderType.ToUpper() == "M";  
  12.   
  13.     public bool IsFemale =>  
  14.         this.genderType.ToUpper() == "Female" || this.genderType.ToUpper() == "F";  
  15. }  

Client code (Test in this case) doesn’t need to change even though the internal representation of the class has changed.

Source Code

GitHub


Similar Articles