The main goal of Vogen is to ensure the validity of your Value Objects.
It does this with code analyzers that add constraints to C#. The analyzers spot situations where you might end up with uninitialized Value Objects. These analyzers, by default, cause compilation errors.
An example violation is where you attempt to add a constructor to your Value Object. In the types tha that Vogen creates, there is one, and only one, way of creating instances, and that is with generated From method. Relying on user-provided constructors could mean that you forget to set or validate the value. Vogen spots when you create your own constructors and causes a compilation error:
[ValueObject]
public partial struct CustomerId
{
// error CS0111: Type 'CustomerId' already defines a member called
// 'CustomerId' with the same parameter type
// That's because Vogen deliberately generates this
// so that you can't create your own.
public CustomerId() { }
// error VOG008: Cannot have user defined constructors, please use
// the From method for creation.
public CustomerId(int value) { }
}
Here's some of the issues that Vogen will spot when creating or consuming Value Objects:
// --- catches object creation expressions
// error VOG010: Type 'CustomerId' cannot be constructed
// with 'new' as it is prohibited
var c = new CustomerId();
// error VOG009: ... cannot be constructed with default ...
CustomerId c = default;
// error VOG009: ... cannot be constructed with default ...
var c = default(CustomerId);
// error VOG010: ... cannot be constructed with 'new' ...
var c = GetCustomerId();
// error VOG025: Type 'CustomerId' cannot be constructed via Reflection
var c = Activator.CreateInstance<CustomerId>();
// error VOG025: Type 'MyVo' cannot be constructed via Reflection
var c = Activator.CreateInstance(typeof(CustomerId));
// catches lambda expressions, e.g.
// error VOG009: Type 'CustomerId' cannot be constructed with default
Func<CustomerId> f = () => default;
// --- catches method / local function return expressions, e.g.
// error VOG009: Type 'CustomerId' cannot be constructed with default
CustomerId GetCustomerId() => default;
// error VOG010: Type 'CustomerId' cannot be constructed with 'new'
CustomerId GetCustomerId() => new CustomerId();
// error VOG010: Type 'CustomerId' cannot be constructed with 'new'
CustomerId GetCustomerId() => new();
// --- catches argument / parameter expressions
// error VOG010: Type 'CustomerId' cannot be constructed with 'new'
Task<CustomerId> t = Task.FromResult<CustomerId>(new());
// error VOG009: Type 'CustomerId' cannot be constructed with default
void Process(CustomerId customerId = default) { }
One of the main goals of Vogen is to achieve almost the same speed and memory performance as using primitives directly. Put another way, if your decimal primitive represents an Account Balance, then there is extremely low overhead of using an AccountBalance Value Object instead. Please see the performance metrics for more information.
How this documentation is organized
These top level pages discuss key topics and concepts at a fairly high level and provide useful background information and explanation.
Tutorials—take you by the hand through a series of steps to create an application that uses Vogen. Start here if you're new to Vogen.
Reference guides-contains technical reference for Vogen usage, describing how it works and how to use it. The Assumption is that you have a basic understanding of key concepts.
How-to guides—recipes guiding you through the steps involved in addressing key problems and use-cases. They are more advanced than tutorials, and they assume some knowledge of how Vogen works.