Я работаю над системой проверки, которую планирую вскоре выпустить в сообщество. По сути, это реализация шаблона Specification .
Базовый интерфейс предназначен для функционального характера:
public interface ICheckable<T>
{
CheckResult Apply(T target);
}
CheckResult
- это struct
, представляющее значение в трех состояниях: Passed
, Failed
и Ignored
. Все преобразования и операторные перегрузки используются для обработки значения Boolean
.
Это позволяет валидаторам выражать «У меня нет мнения» вместо того, чтобы возвращать вводящее в заблуждение значение true
(думаю, RangeValidator
означает, что пустое поле является действительным, поэтому оно хорошо сочетается с RequiredFieldValidator
).
Композиция происходит естественным образом и выполняется со статическими классами в стиле Linq. Каждая точка в проверке является неявной And
следующей операции:
public static ICheckable<T> Add<T>(this ICheckable<T> check, ICheckable<T> otherCheck)
{
return new Check<T>(t => check.Apply(t) && otherCheck.Apply(t));
}
public static ICheckable<T> Either<T>(this ICheckable<T> check, ICheckable<T> firstCheck, ICheckable<T> secondCheck)
{
return check.Add(t => firstCheck.Apply(t) || secondCheck.Apply(t));
}
public static ICheckable<T> Not<T>(this ICheckable<T> check, ICheckable<T> negatedCheck)
{
return check.Add(t => !negatedCheck.Apply(t));
}
Методы расширения работают хорошо:
public static ICheckable<int> Percentage(this ICheckable<int> check)
{
return check.Add(n => n >= 0 && n <= 100);
}
public static ICheckable<T> GreaterThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
return check.Add(t => t.CompareTo(value) >= 0);
}
public static ICheckable<T> LessThanOrEqualTo<T>(this ICheckable<T> check, T value) where T : IComparable<T>
{
return check.Add(t => t.CompareTo(value) <= 0);
}
public static ICheckable<T> Range<T>(this ICheckable<T> check, T minimum, T maximum) where T : IComparable<T>
{
return check.GreaterThanOrEqualTo(minimum).LessThanOrEqualTo(maximum);
}
// RangeExcludeMinimum
// RangeExcludeMaximum
// RangeExclusive
Каждая операция включает в себя перегрузки, которые принимают лямбда проверки построения:
public static ICheckable<T> Add<T>(this ICheckable<T> check, Func<ICheckable<T>, ICheckable<T>> makeCheck)
{
return check.Add(makeCheck(new IgnoredCheck<T>()));
}
Таким образом, вы можете сделать синтаксис следующим образом:
ICheckable<int> check;
check.Add(i => i.Percentage().GreaterThan(50).Even());