这是一个绝妙的想法,它激发了我围绕这个想法实现一种基于扩展方法的验证框架。
我创建了以下验证类(为简洁起见删除了其他验证):
public static class Validation
{
public static bool IsValid<T>(this T _)
{
return true;
}
public static T NotNull<T>(T @value, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value == null) throw new ArgumentNullException(thisExpression);
return value;
}
public static string LengthBetween(this string @value, int min, int max, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value.Length < min) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have less than {min} items");
if (value.Length > max) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have more than {max} items");
return value;
}
public static IComparable<T> RangeWithin<T>(this IComparable<T> @value, T min, T max, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value.CompareTo(min) < 0) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have less than {min} items");
if (value.CompareTo(max) > 0) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have more than {max} items");
return value;
}
}
然后您可以将其与以下内容一起使用:
// FirstName may not be null and must be between 1 and 5
// LastName may be null, but when it is defined it must be between 3 and 10
// Age must be positive and below 200
record Person(string FirstName, string? LastName, int Age, Guid Id)
{
private readonly bool _valid = Validation.NotNull(FirstName).LengthBetween(1, 5).IsValid() &&
(LastName?.LengthBetween(2, 10).IsValid() ?? true) &&
Age.RangeWithin(0, 200).IsValid();
}
?? true 非常重要,这是为了确保在可为空的 LastName 确实为空的情况下继续验证,否则它会短路。
也许使用另一个静态 AllowNull 方法来包装该变量的整个验证会更好(更安全),如下所示:
public static class Validation
{
public static bool IsValid<T>(this T _)
{
return true;
}
public static bool AllowNull<T>(T? _)
{
return true;
}
public static T NotNull<T>(T @value, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value == null) throw new ArgumentNullException(thisExpression);
return value;
}
public static string LengthBetween(this string @value, int min, int max, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value.Length < min) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have less than {min} items");
if (value.Length > max) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have more than {max} items");
return value;
}
public static IComparable<T> RangeWithin<T>(this IComparable<T> @value, T min, T max, [CallerArgumentExpression("value")] string? thisExpression = default)
{
if (value.CompareTo(min) < 0) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have less than {min} items");
if (value.CompareTo(max) > 0) throw new ArgumentOutOfRangeException(thisExpression, $"Can't have more than {max} items");
return value;
}
}
record Person(string FirstName, string? LastName, int Age, Guid Id)
{
private readonly bool _valid = Validation.NotNull(FirstName).LengthBetween(1, 5).IsValid() &&
Validation.AllowNull(LastName?.LengthBetween(2, 10)) &&
Age.RangeWithin(0, 200).IsValid();
}
仍然不太喜欢那部分,但除此之外,我认为它很酷!虽然还没有实际测试过:)所以要小心!