zoukankan      html  css  js  c++  java
  • 实现一个对象验证库系列 -- 2) 验证器实现 (请大神批评)

    前情回顾:

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

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

    2) 验证器实现

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

    public class Validator : IValidator
    {
    	public IValidateResult Validate(ValidateContext context)
    	{
    	}
    }
    

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

    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;
    	}
    }
    

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

    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;
    	}
    }
    

      

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

    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);
    	}
    }
    

      

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

    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>();
    	}
    }
    

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

    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以及扩展方法实现

  • 相关阅读:
    css选择器中:first-child与:first-of-type的区别
    Chrome 快捷键
    notepad++ html格式化
    Linux VFS的主要的数据结构
    Linux根文件系统介绍
    Linux文件系统测试工具
    p​o​s​t​m​a​r​k​使​用
    虚拟文件系统
    linux文件系统初始化过程(6)---执行init程序
    linux文件系统初始化过程(4)---加载initrd(中)
  • 原文地址:https://www.cnblogs.com/fs7744/p/4897280.html
Copyright © 2011-2022 走看看