Skip to content

[API Proposal]: Add a RangeAttribute constructor supporting arbitrary IComparable ranges. #82526

@eiriktsarpalis

Description

@eiriktsarpalis

Background and motivation

The RangeAttribute currently supports int and double ranges out of the box using dedicated constructor overloads, however any other range necessitates using this overload requiring the operand type as well as string formatted representations of the lower and upper bounds. This only works for types supported by the TypeConverter class expressing limits in strings forces concerns around culture-sensitive formatting:

public class TimeSpanRangeAttribute : RangeAttribute
{
    public TimeSpanRangeAttribute(int minMilliseconds, int maxMilliseconds)
        : base(type: typeof(TimeSpan),
               minimum: TimeSpan.FromMilliseconds(minMilliseconds).ToString("c"),
               maximum: TimeSpan.FromMilliseconds(maxMilliseconds).ToString("c"))
    {
        ParseLimitsInInvariantCulture = true;
    }
}

I've been working on a prototype that adds a protected constructor which accepts arbitrary IComparable bounds directly.

API Proposal

namespace System.ComponentModel.DataAnnotations;

public partial class RangeAttribute
{
    public RangeAttribute(int minimum, int maximum);
    public RangeAttribute(double minimum, double maximum);
+   public RangeAttribute(IComparable minimum, IComparable maximum);

    [RequiresUnreferencedCode("Generic TypeConverters may require the generic types to be annotated.")]
    public RangeAttribute(Type type, string minimum, string maximum);
}

API Usage

The above example is now rendered as follows:

public class TimeSpanMillisecondRangeAttribute : RangeAttribute
{
    public TimeSpanMillisecondRangeAttribute(int minimumMs, int maximumMs)
        : base(TimeSpan.FromMilliseconds(minimumMs), TimeSpan.FromMilliseconds(maximumMs))
    { }
}

Alternative Designs

  • I marked the proposed constructor as protected, since marking it public would add OOTB support for things like string or long ranges using their built-in IComparable implementation. Marking it protected emphasizes its use as an extensibility point for user-defined derived validation attributes. If people thinks it is useful, we could mark as public instead.
  • Proposal leaves out IComparer support since the validator implementation is oriented around handling of IComparable values.

Risks

No response

cc @geeknoid @jeffhandley

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions