Value Objects

This outline describes the concept of Value Objects (VOs) in the context of the vogen codebase, found at https://github.com/stevedunn/vogen.serialization.

What are Value Objects?

Value Objects are objects whose identity is solely determined by their attributes. Two value objects are considered equal if they have the same value for all their attributes. This contrasts with reference objects, where identity is determined by their location in memory.

How are Value Objects Implemented in C#?

In C#, Value Objects are typically implemented using structs. Structs are value types that are passed by value, meaning a copy of the struct is created when passed as an argument to a method or returned from a method. This helps to ensure immutability, as changes made to a copy of the struct do not affect the original.

Benefits of Using Value Objects

  • Immutability: VOs are inherently immutable, meaning their state cannot be changed after creation. This promotes thread safety and simplifies reasoning about object behavior.
  • Equality: Clear and consistent definition of equality based on attribute values, making it easy to compare objects.
  • Data Encapsulation: VOs encapsulate data and behavior, promoting modularity and code reusability.
  • Type Safety: VOs can enforce specific data types and constraints, reducing the risk of errors.

How Vogen Generates Value Objects

The vogen tool generates C# code for Value Objects from a simple configuration file. The generated code includes:

  • Immutable properties: All properties of the generated VO are readonly.
  • Constructor: A constructor to initialize all properties.
  • Equality implementation: The generated VO overrides the Equals, GetHashCode, and operator== methods to ensure correct equality comparisons.

Example Value Object

public readonly struct EmployeeId : IEquatable<EmployeeId>
          {
              public int Id { get; }
          
              public EmployeeId(int id)
              {
                  Id = id;
              }
          
              public override bool Equals(object obj)
              {
                  return obj is EmployeeId other && Equals(other);
              }
          
              public bool Equals(EmployeeId other)
              {
                  return Id == other.Id;
              }
          
              public override int GetHashCode()
              {
                  return Id.GetHashCode();
              }
          
              public static bool operator ==(EmployeeId left, EmployeeId right)
              {
                  return left.Equals(right);
              }
          
              public static bool operator !=(EmployeeId left, EmployeeId right)
              {
                  return !(left == right);
              }
          }
          

This is an example of a generated VO representing an EmployeeId. This generated VO is immutable, implements the IEquatable interface, and overrides Equals, GetHashCode, and the == and != operators to support correct equality comparisons.

Conclusion

Value Objects are a powerful tool for building robust and maintainable software. By leveraging the principles of immutability and equality, Value Objects help to promote clarity, consistency, and safety in your codebase. The vogen tool simplifies the process of creating Value Objects in C#, allowing developers to focus on business logic instead of boilerplate code.