Skip to main content
Version: 0.3.x (0.3.0)

Interface IValueObject<TSelf, TValue>

Namespace: AdCodicem.ValueObjects
Assembly: AdCodicem.ValueObjects.Abstractions.dll

The full contract of a single-value value object, self-referencing so that construction, parsing and comparison are resolved statically without reflection or boxing.

public interface IValueObject<TSelf, TValue> : IValueObject<TValue>, IValueObject, IEquatable<TSelf>, IComparable<TSelf>, IComparable, ISpanParsable<TSelf>, IParsable<TSelf>, ISpanFormattable, IFormattable where TSelf : struct, IValueObject<TSelf, TValue>

Type Parameters​

TSelf

The value object type itself.

TValue

Underlying value type.

Implements​

IValueObject<TValue>, IValueObject, IEquatable<TSelf>, IComparable<TSelf>, IComparable, ISpanParsable<TSelf>, IParsable<TSelf>, ISpanFormattable, IFormattable

Remarks​

Implementations are expected to be readonly partial structs produced by the AdCodicem.ValueObjects.Generators source generator. Writing one by hand is supported but tedious.

The construction pipeline is always Normalize then Validate then assign, so a non-default instance is by construction both normalized and valid.

Properties​

IsDefault​

Gets a value indicating whether this instance equals default(TSelf).

bool IsDefault { get; }

Property Value​

bool

Remarks​

Over a reference type (), that is exactly an instance that never went through Create. Over a value type, a constructed instance holding the type's zero (0, , …) also equals the default and reads true; only the VO0010 analyzer and validation tell them apart.

default(TSelf) and new TSelf() bypass validation because the CLR always allows them for a struct. The analyzers shipped with AdCodicem.ValueObjects report those expressions as errors (VO0010); this property is the run-time guard for values that cross a boundary the analyzer cannot see.

A generated value object implements it explicitly, so that a tool reading the public instance properties of the type finds Value alone. Generic code constrained on this interface reads it without boxing; code holding the concrete type calls such generic code, or casts to the interface, which boxes.

Schema​

Gets the declarative constraints of the value object, shared by validation, OpenAPI and persistence.

public static abstract ValueObjectSchema Schema { get; }

Property Value​

ValueObjectSchema

Remarks​

The generator emits it from the options and hooks the value object declares, and registers the same instance as the of its descriptor. Generic code constrained on this interface reads it through its type parameter, TSelf.Schema.MaxLength, with no registry to look the type up in: a construction of a generic value object, which the registry describes by reflection, included.

A value object written by hand declares it, with the rules its Validate enforces, or when it publishes none. The registry describes such a type from this property, whatever annotation it carries.

Methods​

Create(TValue)​

Normalizes, validates, and creates a value object.

public static abstract TSelf Create(TValue value)

Parameters​

value TValue

Candidate value.

Returns​

TSelf

The created value object.

Exceptions​

ValueObjectException

value violates one of the rules.

CreateUnchecked(TValue)​

Creates a value object from a value that is already known to be normalized and valid.

public static abstract TSelf CreateUnchecked(TValue value)

Parameters​

value TValue

Trusted value.

Returns​

TSelf

The created value object.

Remarks​

This is the trusted-source fast path: it performs no work at all. It is used when materializing entities from a database the application itself wrote to. Feeding it unvalidated input defeats the whole point of the type.

Normalize(TValue)​

Normalizes a candidate value into its canonical form.

public static abstract TValue Normalize(TValue value)

Parameters​

value TValue

Candidate value.

Returns​

TValue

The canonical form of value.

Remarks​

Normalization must be idempotent: Normalize(Normalize(x)) equals Normalize(x). It must not reject values — an unnormalizable value is rejected by instead.

TryCreate(TValue, out TSelf)​

Normalizes, validates, and creates a value object without throwing.

public static abstract bool TryCreate(TValue value, out TSelf result)

Parameters​

value TValue

Candidate value.

result TSelf

The created value object, or default when the value is rejected.

Returns​

bool

true when value was accepted.

TryCreate(TValue, out TSelf, out ValidationResult)​

Normalizes, validates, and creates a value object without throwing, reporting why a value was rejected.

public static abstract bool TryCreate(TValue value, out TSelf result, out ValidationResult validation)

Parameters​

value TValue

Candidate value.

result TSelf

The created value object, or default when the value is rejected.

validation ValidationResult

The outcome of the validation.

Returns​

bool

true when value was accepted.

TryParse(ReadOnlySpan<char>, IFormatProvider?, out TSelf, out ValidationResult)​

Parses text without throwing, reporting why the text was rejected.

public static abstract bool TryParse(ReadOnlySpan<char> text, IFormatProvider? provider, out TSelf result, out ValidationResult validation)

Parameters​

text ReadOnlySpan<char>

Text to parse.

provider IFormatProvider?

Format provider used to parse the underlying value.

result TSelf

The parsed value object, or default when the text is rejected.

validation ValidationResult

The outcome, distinguishing text that does not even have the shape of the underlying type from text that parses but breaks one of the type's rules.

Returns​

bool

true when the text was accepted.

Remarks​

This is what every boundary wants: model binding, configuration binding and data readers all need to tell the caller which rule was violated, not merely that something went wrong.

Validate(in TValue)​

Validates an already normalized candidate value.

public static abstract ValidationResult Validate(in TValue value)

Parameters​

value TValue

Normalized candidate value.

Returns​

ValidationResult

The outcome of the first violated rule, or .