实现一个对象验证库系列 -- 2) 验证器实现 (请大神批评)

前情回顾:

上一篇 1) 接口介绍以及总体思路概述 简单描述了下库的设计思路

本文将说说验证器实现,欢迎大神指导更快更好的方案

2) 验证器实现

我们首先从用户调用的验证器开始实现,所以我们应该首先这样做

1
2
3
4
5
6
public class Validator : IValidator
{
    public IValidateResult Validate(ValidateContext context)
    {
    }
}

但是我们的验证器不是没有规则嘛?回忆一下我们好像是在为 Fluent 设计时添加了一个验证器设置规则的接口,所以我们应这样实现验证器:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
public class Validator : IValidatorSetter
{
    private List<IValidateRule> m_Rules
       = new List<IValidateRule>();   // 保存验证规则
 
    public void SetRules(IEnumerable<IValidateRule> rules)
    {
        ParamHelper.CheckParamNull(rules, "rules", "Can't be null");
        m_Rules.AddRange(rules);    // 添加验证规则
    }
 
    public IValidateResult Validate(ValidateContext context)
    {
        ParamHelper.CheckParamNull(context, "context", "Can't be null");
         
        var list = context.RuleSetList;
        if (!list.IsEmptyOrNull())
        {
            context.RuleSetList = list.Where(i => !string.IsNullOrEmpty(i)).Select(i => i.ToUpper()).ToArray();
        }
        // 处理验证规则分组标志筛选列表
         
        var rules = m_Rules.Where(i => context.RuleSelector.CanExecute(i, context)).ToArray();
        // 筛选验证规则
         
         
        var result = Container.Resolve<IValidateResult>();
        if (!rules.IsEmptyOrNull())
        {
            var tasks = rules.Select(i => Task.Factory.StartNew(() => i.Validate(context))).ToArray();
            Task.WaitAll(tasks);
            // 执行验证
 
            if (tasks.Any(i => i.IsFaulted))
            {
                var exceptions = tasks.Where(i => i.IsFaulted)
                                    .Select(i => i.Exception);
                throw new AggregateException(exceptions);
            }
            // 处理task 的异常情况
 
            var failures = tasks.Where(i => i.IsCompleted)
                                .SelectMany(i => i.Result.Failures);
            result.Merge(failures);
            // 处理 验证结果
        }
 
        return result;
    }
}

 

接着我们再实现验证规则:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
public class ValidateRule : IValidateRule
{
    public IValidateRule NextRule { get; set; }
 
    public string RuleSet { get; set; }
 
    public string ValueName { get; set; }
 
    public string Error { get; set; }
 
    public Func<ValidateContext, bool> Condition { get; set; }
 
    public Func<ValidateContext, string, string, IValidateResult> ValidateFunc { get; set; }
 
    public IValidateResult Validate(ValidateContext context)
    {
        ParamHelper.CheckParamNull(ValidateFunc, "ValidateFunc", "Can't be null");
        ParamHelper.CheckParamNull(context, "context", "Can't be null");
        IValidateResult result = null;
        if (Condition == null || Condition(context))  // 判断用户的特殊过滤条件
        {
            result = ValidateByFunc(context);         // 执行规则的验证
        }
        else
        {
            result = Container.Resolve<IValidateResult>();
        }
        return result;
    }
 
    public IValidateResult ValidateByFunc(ValidateContext context)
    {
        IValidateResult result = ValidateFunc(context, ValueName, Error); //执行当前规则的验证逻辑
         
        var nextRule = NextRule;
        if (nextRule != null
            && (result.IsValid || context.Option == ValidateOption.Continue))  // 判断是否有必要执行子级验证规则
        {
            var nextResult = nextRule.Validate(context);  // 执行子级验证规则
            result.Merge(nextResult.Failures);       // 处理子级验证结果
        }
 
        return result;
    }
}

  

等等,好像我们还没有实现验证规则分组标志筛选器,好吧,我们实现它吧

1
2
3
4
5
6
7
8
9
10
public class RuleSelector : IRuleSelector
{
    public bool CanExecute(IValidateRule rule, ValidateContext context)
    {
        return string.IsNullOrEmpty(rule.RuleSet)
            || context.RuleSetList.IsEmptyOrNull()
                ? true
                : context.RuleSetList.Contains(rule.RuleSet);
    }
}

  

我们把目前的实现与接口绑定到容器中:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
public static class Container
{
    public static ILifetimeScope CurrentScope { get; set; }
 
    public static void Init(Action<ContainerBuilder> action)
    {
        ParamHelper.CheckParamNull(action, "action", "Can't be null");
        Clear();
        var builder = new ContainerBuilder();
        action(builder);
        var container = builder.Build();
        CurrentScope = container.BeginLifetimeScope();
    }
 
    public static void Init()
    {
        Init(builder =>
        {
            // 绑定接口
            builder.RegisterType<RuleSelector>().As<IRuleSelector>().SingleInstance();
            builder.Register(c => new ValidateContext() { RuleSelector = c.Resolve<IRuleSelector>() });
            builder.RegisterType<ValidateRule>().As<IValidateRule>().InstancePerDependency();
            builder.RegisterType<ValidateResult>().As<IValidateResult>().InstancePerDependency();
            builder.RegisterType<Validator>().As<IValidatorSetter>().InstancePerDependency();
        });
    }
 
    public static void Clear()
    {
        var scope = CurrentScope;
        if (scope != null)
            scope.Dispose();
    }
 
    public static T Resolve<T>()
    {
        return CurrentScope.Resolve<T>();
    }
}

 

好吧,我们来简单试试吧:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Container.Init(); // 初始接口
 
var v = new Validator();
var rule = new ValidateRule()
{
    ValidateFunc = (c, name, error) =>
    {
        var f = new ValidateFailure()
        {
            Name = name,
            Error = error,
            Value = c
        };
        return new ValidateResult(new List<ValidateFailure>() { f });
    }
};
v.SetRules(new List<ValidateRule>() { rule });
// 简单设置验证
 
 
var context = new ValidateContext() { RuleSelector = new RuleSelector() };
var result = v.Validate(context);
// 试用一下
 
Assert.IsNotNull(result);
Assert.True(result.IsValid);
Assert.IsNotNull(result.Failures);
Assert.AreEqual(0, result.Failures.Count);

 

好吧,没有实现 Fluent 设置验证规则的代码,现在整体看起来真丑啊

 

NEXT: 3) Fluent以及扩展方法实现

posted @   victor.x.qu  阅读(1001)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
点击右上角即可分享
微信分享提示