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

Class ValueObjectDescriptor

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

Runtime description of a value object type, used by the integrations that only know a .

public sealed class ValueObjectDescriptor

Inheritance​

object ← ValueObjectDescriptor

Inherited Members​

object.Equals(object?), object.Equals(object?, object?), object.GetHashCode(), object.GetType(), object.ReferenceEquals(object?, object?), object.ToString()

Remarks​

The delegates it exposes operate on boxed values, which is acceptable because every one of them is invoked during start-up work — building the EF Core model, generating an OpenAPI document, registering a Dapper type handler — never on a per-request path. Request paths go through the strongly typed generic APIs.

Descriptors are produced by , which is fully generic and therefore free of reflection: the source generator emits one call per value object in a module initializer.

A caller that needs the type arguments themselves, to close an adapter of its own over the value object, gets them back through , again without reflection.

Properties​

Create​

Gets the validating factory. Throws on a rejected value.

public Func<object?, object> Create { get; }

Property Value​

Func<object?, object>

Remarks​

A null is rejected as whatever the underlying type: a string value object rejects it through its own rule, and a value-typed underlying value has no null to accept.

CreateUnchecked​

Gets the trusted-source factory, which performs neither normalization nor validation.

public Func<object?, object> CreateUnchecked { get; }

Property Value​

Func<object?, object>

Format​

Gets the invariant text representation of a boxed value object.

public Func<object, string> Format { get; }

Property Value​

Func<object, string>

Remarks​

It takes a boxed instance of , never null: the null of a nullable value object throws a here. A caller holding a TSelf? handles its null first.

GetValue​

Gets the accessor returning the boxed underlying value of a boxed value object.

public Func<object, object?> GetValue { get; }

Property Value​

Func<object, object?>

Remarks​

It takes a boxed instance of , never null: the null of a nullable value object throws a here. A caller holding a TSelf? handles its null first.

JsonConverter​

Gets the System.Text.Json converter of the value object, when its registration supplied one.

public JsonConverter? JsonConverter { get; }

Property Value​

JsonConverter?

Remarks​

The generator emits a converter for every value object and registers how to create it here, whatever the declaring assembly references. ValueObjectJsonConverterFactory hands it to a source-generated serializer context, whose generator never sees the [JsonConverter] attribute on the type, so that no converter has to be built by reflection, which trimming and native AOT do not support. It is created the first time it is asked for, and the same instance is handed out from then on.

Schema​

Gets the declarative constraints of the value object.

public ValueObjectSchema Schema { get; }

Property Value​

ValueObjectSchema

TryCreate​

Gets the non-throwing validating factory.

public BoxedTryCreate TryCreate { get; }

Property Value​

BoxedTryCreate

Remarks​

A null is rejected as whatever the underlying type, as it is by .

TryParse​

Gets the non-throwing text parser.

public BoxedTryParse TryParse { get; }

Property Value​

BoxedTryParse

ValidateWrite​

Gets the check a boundary runs on a boxed value object before it writes it: the outcome of the first rule the value it holds violates, or .

public Func<object, ValidationResult> ValidateWrite { get; }

Property Value​

Func<object, ValidationResult>

Remarks​

A writer refuses what fails it, rather than write a value its type rejects, which a reader would then trust: the Newtonsoft.Json converter throws, as the generated System.Text.Json converter, the Dapper handler and the Entity Framework Core converters do for a value object they know by its type.

Only an instance equal to default(TSelf) is validated, as its value stands: it is the one an instance that never went through Create holds. Over a value type, a constructed zero equals the default too, and validation tells a valid zero from a refused one. Any other instance passes without being validated again.

It takes a boxed instance, never null, as does.

ValueObjectType​

Gets the value object type.

public Type ValueObjectType { get; }

Property Value​

Type

ValueType​

Gets the underlying value type.

public Type ValueType { get; }

Property Value​

Type

Methods​

Accept<TResult>(IValueObjectVisitor<TResult>)​

Hands the type arguments the descriptor was built with to a visitor, which closes its own generic code over them.

public TResult Accept<TResult>(IValueObjectVisitor<TResult> visitor)

Parameters​

visitor IValueObjectVisitor<TResult>

The visitor, whose is called with and .

Returns​

TResult

What the visitor returned.

Type Parameters​

TResult

What the visitor hands back.

Remarks​

This is the typed way out of a descriptor. An integration that finds value objects by creates its adapter in the visitor, closed at compile time, where would close it at run time, which native AOT cannot do for a struct:

sealed class FormatterFor : IValueObjectVisitor<IFormatter>
{
public IFormatter Visit<TSelf, TValue>() where TSelf : struct, IValueObject<TSelf, TValue>
=> new ValueObjectFormatter<TSelf, TValue>();
}

var formatter = descriptor.Accept(new FormatterFor());

Every descriptor carries its type arguments, whoever built it: the generated registration, a registration by hand, or describing a type by reflection, whose descriptor only the JIT can visit. A descriptor built for a value object over is visited like any other: a visitor skips what its host cannot carry.

Exceptions​

ArgumentNullException

visitor is null.

For<TSelf, TValue>(ValueObjectSchema)​

Builds a descriptor for a value object, resolving every operation statically.

public static ValueObjectDescriptor For<TSelf, TValue>(ValueObjectSchema schema) where TSelf : struct, IValueObject<TSelf, TValue>

Parameters​

schema ValueObjectSchema

Declarative constraints of the value object.

Returns​

ValueObjectDescriptor

The descriptor.

Type Parameters​

TSelf

Value object type.

TValue

Underlying value type.

For<TSelf, TValue>(ValueObjectSchema, Func<JsonConverter<TSelf>>?)​

Builds a descriptor for a value object carrying its System.Text.Json converter, resolving every operation statically.

public static ValueObjectDescriptor For<TSelf, TValue>(ValueObjectSchema schema, Func<JsonConverter<TSelf>>? jsonConverter) where TSelf : struct, IValueObject<TSelf, TValue>

Parameters​

schema ValueObjectSchema

Declarative constraints of the value object.

jsonConverter Func<JsonConverter<TSelf>>?

Creates the converter of the value object, the first time is read, or null when its registration supplies none.

Returns​

ValueObjectDescriptor

The descriptor.

Type Parameters​

TSelf

Value object type.

TValue

Underlying value type.