Skip to content

Expo Property Comparisons

SteffenBlake edited this page Sep 28, 2026 · 1 revision

Property comparisons

Mark a property with [IsComparable] to generate attributes that compare other properties against it. Use these rules for related bounds such as minimum and maximum capacity.

Compare two properties

// CourseCapacityRange.cs
[Expo]
public sealed partial class CourseCapacityRange
{
    [IsComparable]
    [IsGreaterThanOrEqualTo(1)]
    public int MinimumCapacity { get; init; }

    [IsGreaterThanOrEqualToMinimumCapacity("Maximum capacity must meet the minimum.")]
    public int MaximumCapacity { get; init; }
}

[IsComparable] makes MinimumCapacity available as a comparison target. It does not impose a rule by itself. The constant rule still checks that the minimum is positive.

The generated rule on MaximumCapacity requires it to be at least MinimumCapacity. Its failure points to /MaximumCapacity, the property carrying the rule.

Generated names

For a target named MinimumCapacity, Expo generates:

Attribute Required relationship
[IsGreaterThanMinimumCapacity] Greater than the target
[IsGreaterThanOrEqualToMinimumCapacity] Greater than or equal to the target
[IsLessThanMinimumCapacity] Less than the target
[IsLessThanOrEqualToMinimumCapacity] Less than or equal to the target
[IsEqualToMinimumCapacity] Equal to the target
[IsNotEqualToMinimumCapacity] Different from the target

Each accepts an optional message. The attributes are private to the model where Expo generates them. Mark the target in each model that needs its own comparison rules.

Compatible types

The compared value must work with the property type's default comparer. Ordering uses Comparer<T>.Default, while equality uses EqualityComparer<T>.Default. Choose compatible types and account for nullable values explicitly.

On a collection property, a generated comparison rule checks each item against the target property. Its errors use indexed pointers. See Collections.

Use the generated concrete attributes. The abstract comparison attribute classes and Is*XAttribute bases support generation and are not the attributes to place directly on application properties.

For rules relating several fields or producing several messages, use Model-specific custom validation.

Clone this wiki locally