只要十步,你就可以应用表达式树来优化动态调用(一)( 八 )
< minLength? ValidateResult.Error($"Length of {name} should be great than {minLength}"): ValidateResult.Ok();}public class CreateClaptrapInput{[Required] [MinLength(3)] public string Name { get; set; }[Required] [MinLength(3)] public string NickName { get; set; }}}}代码要点:
- 在 CreateClaptrapInput 中增加了一个属性 NickName, 测试用例也将验证该属性 。
- 通过 List
我们将更多动态生成的表达式加入到了 Block 中 。 因此 , 我们可以对 Name 和 NickName 都生成验证表达式 。
本节 , 我们将通过 Attribute 来决定验证的细节 。 例如被标记为 Required 是属性才会进行必填验证 。
using System;using System.Collections.Generic;using System.ComponentModel.DataAnnotations;using System.Diagnostics;using System.Linq;using System.Linq.Expressions;using System.Reflection;using FluentAssertions;using NUnit.Framework;// ReSharper disable InvalidXmlDocCommentnamespace Newbe.ExpressionsTests{////// Using Attribute///public class X03PropertyValidationTest05{private const int Count = 10_000;private static Func _func;[SetUp]public void Init(){try{var finalExpression = CreateCore();_func = finalExpression.Compile();Expression> CreateCore(){// exp for inputvar inputExp = Expression.Parameter(typeof(CreateClaptrapInput), "input");// exp for outputvar resultExp = Expression.Variable(typeof(ValidateResult), "result");// exp for return statementvar returnLabel = Expression.Label(typeof(ValidateResult));var innerExps = new List {CreateDefaultResult()};var stringProps = typeof(CreateClaptrapInput).GetProperties().Where(x => x.PropertyType == typeof(string));foreach (var propertyInfo in stringProps){if (propertyInfo.GetCustomAttribute() != null){innerExps.Add(CreateValidateStringRequiredExpression(propertyInfo));}var minlengthAttribute = propertyInfo.GetCustomAttribute();if (minlengthAttribute != null){innerExps.Add(CreateValidateStringMinLengthExpression(propertyInfo, minlengthAttribute.Length));}}innerExps.Add(Expression.Label(returnLabel, resultExp));// build whole blockvar body = Expression.Block(new[] {resultExp},innerExps);// build lambda from bodyvar final = Expression.Lambda>(body,inputExp);return final;Expression CreateDefaultResult(){var okMethod = typeof(ValidateResult).GetMethod(nameof(ValidateResult.Ok));Debug.Assert(okMethod != null, nameof(okMethod) + " != null");var methodCallExpression = Expression.Call(okMethod);var re = Expression.Assign(resultExp, methodCallExpression);/*** final as:* result = ValidateResult.Ok()*/return re;}Expression CreateValidateStringRequiredExpression(PropertyInfo propertyInfo){var requireMethod = typeof(X03PropertyValidationTest05).GetMethod(nameof(ValidateStringRequired));var isOkProperty = typeof(ValidateResult).GetProperty(nameof(ValidateResult.IsOk));Debug.Assert(requireMethod != null, nameof(requireMethod) + " != null");Debug.Assert(isOkProperty != null, nameof(isOkProperty) + " != null");var namePropExp = Expression.Property(inputExp, propertyInfo);var nameNameExp = Expression.Constant(propertyInfo.Name);var requiredMethodExp = Expression.Call(requireMethod, nameNameExp, namePropExp);var assignExp = Expression.Assign(resultExp, requiredMethodExp);var resultIsOkPropertyExp = Expression.Property(resultExp, isOkProperty);var conditionExp = Expression.IsFalse(resultIsOkPropertyExp);var ifThenExp =Expression.IfThen(conditionExp,Expression.Return(returnLabel, resultExp));var re = Expression.Block(new[] {resultExp},assignExp,ifThenExp);return re;}Expression CreateValidateStringMinLengthExpression(PropertyInfo propertyInfo,int minlengthAttributeLength){var minLengthMethod =typeof(X03PropertyValidationTest05).GetMethod(nameof(ValidateStringMinLength));var isOkProperty = typeof(ValidateResult).GetProperty(nameof(ValidateResult.IsOk));Debug.Assert(minLengthMethod != null, nameof(minLengthMethod) + " != null");Debug.Assert(isOkProperty != null, nameof(isOkProperty) + " != null");var namePropExp = Expression.Property(inputExp, propertyInfo);var nameNameExp = Expression.Constant(propertyInfo.Name);var requiredMethodExp = Expression.Call(minLengthMethod,nameNameExp,namePropExp,Expression.Constant(minlengthAttributeLength));var assignExp = Expression.Assign(resultExp, requiredMethodExp);var resultIsOkPropertyExp = Expression.Property(resultExp, isOkProperty);var conditionExp = Expression.IsFalse(resultIsOkPropertyExp);var ifThenExp =Expression.IfThen(conditionExp,Expression.Return(returnLabel, resultExp));var re = Expression.Block(new[] {resultExp},assignExp,ifThenExp);return re;}}}catch (Exception e){Console.WriteLine(e);throw;}}[Test]public void Run(){// see code in demo repo}public class CreateClaptrapInput{[Required] [MinLength(3)] public string Name { get; set; }[Required] [MinLength(3)] public string NickName { get; set; }}}}
- 只需799元就可以把旧iPad换成新款iPad?是真的!但这羊毛可没那么容易薅
- 马化腾这招太高明!网友:只要我改名的速度够快,禁令就追不上我
- 飞腾桌面腾锐D2000 CPU发布:最高2.6GHz、八核只要25W
- 苹果官网产品出现 Bug 价:上千元产品显示只要一两百元
- 华为手机为什么耗电快?只要关闭手机这6个开关,2天1充不是梦
- 苏宁易购双十二10亿补贴引爆吃货狂欢,西贝明星单品只要9.9
- 别错过,双节钜惠还有2天结束
- 人群|出差旅行也能带呼吸机?M1 Mini就可以
- 瑞士宽带商TWiFi可提供18年免费上网服务
- 5G新选择:支持65W快充,8G+128G只要1599元