Table of Contents

Interface IScalarValue<TSelf, TPrimitive>

Namespace
Trellis
Assembly
Trellis.Results.dll

Interface for scalar value objects that can be created with validation. Enables automatic ASP.NET Core model binding and JSON serialization.

public interface IScalarValue<TSelf, TPrimitive> where TSelf : IScalarValue<TSelf, TPrimitive> where TPrimitive : IComparable

Type Parameters

TSelf

The value object type itself (CRTP pattern)

TPrimitive

The underlying primitive type (must be IComparable)

Examples

Implementing in a custom value object:

public class EmailAddress : ScalarValueObject<EmailAddress, string>, IScalarValueObject<EmailAddress, string>
{
    private EmailAddress(string value) : base(value) { }

    public static Result<EmailAddress> TryCreate(string value, string? fieldName = null) =>
        value.ToResult(Error.Validation("Email is required", fieldName ?? "email"))
            .Ensure(e => e.Contains("@"), Error.Validation("Invalid email", fieldName ?? "email"))
            .Map(e => new EmailAddress(e));
}

Remarks

This interface uses the Curiously Recurring Template Pattern (CRTP) to enable static abstract methods on the value object type. This allows model binders and JSON converters to call TryCreate(TPrimitive, string?) without reflection.

When a type implements this interface, it can be automatically validated during:

  • ASP.NET Core model binding (from route, query, form, or header values)
  • JSON deserialization (from request body)

Properties

Value

Gets the underlying primitive value for serialization.

TPrimitive Value { get; }

Property Value

TPrimitive

The primitive value wrapped by this scalar value.

Methods

Create(TPrimitive)

Creates a validated scalar value from a primitive value. Throws an exception if validation fails.

public static TSelf Create(TPrimitive value)

Parameters

value TPrimitive

The raw primitive value

Returns

TSelf

The validated scalar value

Examples

Use in tests or with known-valid values:

// ✅ Good - Test data
var email = EmailAddress.Create("test@example.com");

// ✅ Good - Building from validated data
var total = Money.Create(item1.Amount + item2.Amount, "USD");

// ❌ Bad - User input (use TryCreate instead)
var email = EmailAddress.Create(userInput);

Remarks

Use this method when you know the value is valid (e.g., in tests, with constants, or when building from other validated values). This provides cleaner code than calling TryCreate().Value.

⚠️ Don't use this method with user input or uncertain data - use TryCreate(TPrimitive, string?) instead to handle validation errors gracefully.

The default implementation calls TryCreate(TPrimitive, string?) and throws if validation fails. You can override this if you need custom error handling behavior.

Exceptions

InvalidOperationException

Thrown when validation fails

TryCreate(TPrimitive, string?)

Attempts to create a validated scalar value from a primitive value.

public static abstract Result<TSelf> TryCreate(TPrimitive value, string? fieldName = null)

Parameters

value TPrimitive

The raw primitive value

fieldName string

Optional field name for validation error messages. If null, implementations should use a default field name based on the type name (e.g., "emailAddress" for EmailAddress type).

Returns

Result<TSelf>

Success with the scalar value, or Failure with validation errors

Remarks

This method is called by model binders and JSON converters to create scalar values with validation. The validation errors are collected and returned through the standard ASP.NET Core validation infrastructure.

When called from ASP.NET Core model binding or JSON deserialization, the fieldName parameter is automatically populated with the property name from the DTO.