C# 基于规则的验证层

C# 基于规则的验证层,c#,validation,generics,design-patterns,C#,Validation,Generics,Design Patterns,我正在努力实现 从打电话的人开始,我想这样做: var validatore = new Validator(); validatore.AddRule<TestRule>("OK"); validatore.AddRule<int>(45); validatore.Validate(); public interface IValidator { void AddRule<TRule>(dynamic arg); ValidationR

我正在努力实现

从打电话的人开始,我想这样做:

var validatore = new Validator();

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

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

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

    public ValidationResult Validate()
    {
        forEach ...
    }
}
var Validator=new Validator();
验证人。添加规则(“确定”);
验证人。添加规则(45);
Validate.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";
    }
}
公共接口验证规则
{
字符串错误{get;set;}
bool验证(T参数);
}
公共类TestRule:IValidationRule
{
公共字符串错误{get;set;}
公共bool验证(字符串arg)
{
返回arg==“测试”;
}
}
问题是验证器的具体实现。 我假设是这样的:

var validatore = new Validator();

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

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

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

    public ValidationResult Validate()
    {
        forEach ...
    }
}
公共接口IValidator
{
void AddRule(动态参数);
ValidationResult Validate();
}
公共类验证器:IValidator
{
公共void AddRule(动态参数)
{
???
}
公共验证结果验证()
{
forEach。。。
}
}
我应该将每个通用规则放在单个集合对象(AddRule)的何处?
我的like实现是否正确?

这种模式一开始就有点过于抽象。从某种意义上说,如果你从你想要做的事情开始,然后在上面进行抽象,那么你最终会得到更有用的概括。比如,在这种情况下,不明显的是,验证了什么?用户在某些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();
    }
}

这种模式一开始就有点过于抽象。从某种意义上说,如果你从你想要做的事情开始,然后在上面进行抽象,那么你最终会得到更有用的概括。比如,在这种情况下,不明显的是,验证了什么?用户在某些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();
    }
}

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