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
TSelfThe value object type itself (CRTP pattern)
TPrimitiveThe 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
valueTPrimitiveThe 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
valueTPrimitiveThe raw primitive value
fieldNamestringOptional 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.