【问题标题】:Validation layer based on rules基于规则的验证层
【发布时间】:2019-06-19 21:28:20
【问题描述】:

我正在尝试实现this pattern

从调用者开始,我想做这样的事情:

var validatore = new Validator();

validatore.AddRule<TestRule>("OK");
validatore.AddRule<int>(45);

validatore.Validate();

规则的执行:

public interface IValidationRule<T>
{
    string Error { get; set; }
    bool Validate(T arg);
}

public class TestRule : IValidationRule<string>
{
    public string Error { get; set; }
    public bool Validate(string arg)
    {
        return arg == "test";
    }
}

问题在于验证器的具体实现。 我假设是这样的:

public interface IValidator
{
    void AddRule<TRule>(dynamic arg);
    ValidationResult Validate();
}

public class Validator : IValidator
{
    public void AddRule<T>(dynamic arg)
    {
        ???
    }

    public ValidationResult Validate()
    {
        forEach ...
    }
}

我应该将每个通用规则放在一个集合对象 (AddRule) 的什么位置? 我的类似实现方式是否正确?

【问题讨论】:

  • 根据您的用例,您可以使用简单的 Collection 或更具体的东西(例如,如果您有多个线程添加验证器,则使用 Concurrentlist),但您可能需要某种 Collection 来保存所有规则你的验证器
  • @Brezelmann,这就是重点。我想我需要某种迭代对象的集合。关键是每个对象都有不同的类型,我不知道如何将它们聚合到一个结构中。
  • 不是每个 Validationrule 都继承自 IValidationRule 接口吗?如果是这样,您可以使用它来使用可以包含 IvalidationRule 的所有可能实现的 Collection。您只需新建您指定为类型的规则,然后将其放入集合中

标签: c# validation generics design-patterns


【解决方案1】:

这个模式有点太抽象了。从某种意义上说,如果您从您想要做的事情开始,然后在此基础上进行抽象,那么您最终会得到更有用的概括。就像,在这种情况下,正在验证什么并不明显?某些 UI 中的用户输入?或者来自一些xml的数据?在第一种情况下,根据您的错误,您不仅需要一条错误消息,还可能需要一些更新 UI 的操作。然后验证抽象可能会采取完全不同的形式。实际代码从哪里来,进行验证?必须为每个验证规则实现特殊的类,这会产生令人讨厌的抽象,但当您真正想要使用它时,代码会变得不必要地复杂。

另外,只有在绝对没有其他方法时,我才会使用动态类型。

因此,假设您仍然感兴趣,下面的代码将用于验证引用类型。再说一次,如果您需要一个验证系统,您需要验证的值类型通常是某个类的属性,但请记住它不是通用的。

public class ValidationResult
{
    public bool HasError { get; set; } = false;
    public string ErrorText { get; set; } = "No error";
    public void SetError(string errorMsg)
    {
        this.HasError = true;
        ErrorText = errorMsg;
    }
}

public interface IValidationRule
{
    ValidationResult Validate();
}

public class ValidationRule<T> : IValidationRule
{
    private Func<T, ValidationResult> validatorFunc;
    private T validationSubject;
    public ValidationRule(T validationSubject, Func<T, ValidationResult> validatorFunc)
    {
        this.validationSubject = validationSubject;
        this.validatorFunc = validatorFunc;
    }

    public ValidationResult Validate() => validatorFunc?.Invoke(validationSubject);
}

public interface IValidator
{
    void AddRule<T>(T validationSubject, Func<T, ValidationResult> validationFunc);
    ValidationResult Validate();
}

public class Validator : IValidator
{
    private readonly List<IValidationRule> rules = new List<IValidationRule>();

    public void AddRule<T>(T validationSubject, Func<T,ValidationResult> validationFunc)
    {
        rules.Add(new ValidationRule<T>(validationSubject, validationFunc));
    }

    public ValidationResult Validate()
    {
        foreach (var rule in rules)
        {
            var result = rule.Validate();
            if (result.HasError) return result;
        }

        return new ValidationResult();
    }
}

要添加验证规则,您需要传入两个参数:一个要在一段时间后验证的对象,以及一个包含逻辑并返回 ValidationResult 的 Func。像这样:

public class ValidatableObject
{
    public int intValue;
}

private void Test()
{
    var target = new ValidatableObject();
    target.intValue = 1;

    var validator = new Validator();
    validator.AddRule(target, (x) =>
    {
        var validationResult = new ValidationResult();
        if (x.intValue > 10) validationResult.SetError("Exceeds max value (10)");
        return validationResult;
    });

    log(validator.Validate().ErrorText);
    target.intValie = 100;
    log(validator.Validate().ErrorText);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2010-11-26
    • 2021-06-24
    • 2017-04-24
    • 1970-01-01
    • 1970-01-01
    • 2015-07-09
    • 2012-06-18
    • 1970-01-01
    相关资源
    最近更新 更多