Alternative Values
Sometimes the refinement process for a type, naturally produces an alternative value.
A good example of this is types that implement IParsable.
For example take DateOnly,
/// <summary>
/// This is a refined string that must be a valid date
/// </summary>
public readonly partial struct DateOnlyString : IEquatable<DateOnlyString>
{
[Refinement("The value must be a valid date, but was '{value}'")]
private static bool DateOnly(string value, out DateOnly dateOnly) =>
System.DateOnly.TryParse(value, out dateOnly);
/// <summary>
/// Some custom function that operates on the refined type
/// </summary>
public bool IsWeekend => AltValue.DayOfWeek is DayOfWeek.Saturday or DayOfWeek.Sunday;
}
This can be used like this,
[Fact(DisplayName = "A string can be refined as a date")]
public void Case1()
{
var refined = (DateOnlyString)"2021-02-28";
// access the raw string
Assert.Equal("2021-02-28", refined.Value);
// access the DateOnly value that was produced from the refinement process
Assert.Equal(new DateOnly(2021, 2, 28), refined.AltValue);
// they can also be split out like this
(string str, DateOnly dte) = refined;
Assert.True(refined.IsWeekend);
Assert.True(
DateOnlyString.TryParse("2021-02-28", out var refined2, out var failureMessage)
);
Assert.Null(failureMessage);
Assert.Equal(refined, refined2);
}
[Fact(DisplayName = "A invalid date string cannot be refined as a date")]
public void Case2()
{
var ex = Assert.Throws<ArgumentOutOfRangeException>(() => (DateOnlyString)"not a date");
Assert.StartsWith("The value must be a valid date, but was 'not a date'", ex.Message);
Assert.False(DateOnlyString.TryParse("not a date", out var refined, out var message));
Assert.Equal("The value must be a valid date, but was 'not a date'", message);
#pragma warning disable TUX001
Assert.Equal(default(DateOnlyString), refined);
#pragma warning restore TUX001
}
This is optimally efficient as it produces the alternative value as a result of the refinement process, as opposed to ensuring that the raw value could be refined (validating it first) and then producing the alternative value (parsing it).