Class RequiredInt<TSelf>
- Namespace
- Trellis
- Assembly
- Trellis.Primitives.dll
Base class for creating strongly-typed integer value objects that cannot have the default (zero) value. Provides a foundation for entity identifiers, counts, and other domain concepts represented by integers.
public abstract class RequiredInt<TSelf> : ScalarValueObject<TSelf, int>, IComparable<ValueObject>, IEquatable<ValueObject>, IConvertible where TSelf : RequiredInt<TSelf>, IScalarValue<TSelf, int>
Type Parameters
TSelf
- Inheritance
-
ScalarValueObject<TSelf, int>RequiredInt<TSelf>
- Implements
- Inherited Members
- Extension Methods
Examples
Creating a strongly-typed entity identifier:
// Define the value object (partial keyword enables source generation)
public partial class TicketNumber : RequiredInt<TicketNumber>
{
}
// The source generator automatically creates:
// - IScalarValue<TicketNumber, int> interface implementation
// - public static Result<TicketNumber> TryCreate(int value, string? fieldName = null)
// - public static Result<TicketNumber> TryCreate(int? value, string? fieldName = null)
// - public static Result<TicketNumber> TryCreate(string? value, string? fieldName = null)
// - public static TicketNumber Parse(string s, IFormatProvider? provider)
// - public static bool TryParse(string? s, IFormatProvider? provider, out TicketNumber result)
// - public static explicit operator TicketNumber(int value)
// - private TicketNumber(int value) : base(value) { }
// Usage examples:
// Create from existing integer with validation
var result1 = TicketNumber.TryCreate(12345);
// Returns: Success(TicketNumber) if value != 0
// Returns: Failure(ValidationError) if value == 0
// Create from string with validation
var result2 = TicketNumber.TryCreate("12345");
// Returns: Success(TicketNumber) if valid integer format
// Returns: Failure(ValidationError) if invalid format or zero
// With custom field name for validation errors
var result3 = TicketNumber.TryCreate(input, "ticket.number");
// Error field will be "ticket.number" instead of default "ticketNumber"
Multiple strongly-typed integer IDs in the same domain:
public partial class InvoiceNumber : RequiredInt<InvoiceNumber> { }
public partial class LineNumber : RequiredInt<LineNumber> { }
public class Invoice
{
public InvoiceNumber Number { get; }
private readonly List<InvoiceLine> _lines = [];
// Compiler prevents mixing IDs:
// AddLine(invoiceNumber); // Won't compile - type safety!
}
Remarks
This class extends ScalarValueObject<TSelf, T> to provide a specialized base for integer-based value objects
with automatic validation that prevents zero/default integers. When used with the partial keyword,
the PrimitiveValueObjectGenerator source generator automatically creates:
IScalarValue<TSelf, int>implementation for ASP.NET Core automatic validationTryCreate(int)- Factory method for integers (required by IScalarValue)TryCreate(int?, string?)- Factory method with zero validation and custom field nameTryCreate(string?, string?)- Factory method for parsing strings with validationIParsable<T>implementation (Parse,TryParse)- JSON serialization support via
ParsableJsonConverter<T> - Explicit cast operator from int
- OpenTelemetry activity tracing
Common use cases:
- Legacy entity identifiers (CustomerId, OrderId when using int IDs)
- Reference numbers (InvoiceNumber, TicketNumber)
- Sequence numbers requiring non-zero values
- Any domain concept requiring a non-zero integer identifier
Benefits over plain integers:
- Type safety: Cannot accidentally use CustomerId where OrderId is expected
- Validation: Prevents zero/default integers at creation time
- Domain clarity: Makes code more self-documenting and expressive
- Serialization: Consistent JSON and database representation
Constructors
RequiredInt(int)
Initializes a new instance of the RequiredInt<TSelf> class with the specified integer value.
protected RequiredInt(int value)
Parameters
valueintThe integer value. Must not be zero.
Remarks
This constructor is protected and should be called by derived classes.
When using the source generator (with partial keyword), a private constructor
is automatically generated that includes validation.
Direct instantiation should be avoided. Instead, use the generated factory methods:
TryCreate(int, string?)- Create from int with validationTryCreate(int?, string?)- Create from nullable int with validationTryCreate(string?, string?)- Create from string with validation