ValidateStringRequiredExp =(name, value) =>string.IsNullOrEmpty(value)? ValidateResult.Error($"missing {name}"): ValidateResult.Ok();private static readonly Expression ValidateStringMinLengthExp =(name, value, minLength) =>value.Length < minLength? ValidateResult.Error($"Length of {name} should be great than {minLength}"): ValidateResult.Ok();}}代码要点:
- 将静态方法换成了表达式 。 因此 CreateXXXExpression 相应的位置也进行了修改 , 代码就更短了 。
第七步 , 柯里化柯理化 , 也称为函数柯理化 , 是函数式编程当中的一种方法 。 简单的可以表述为:通过固定一个多参数函数的一个或几个参数 , 从而得到一个参数更少的函数 。 术语化一些 , 也可以表述为将高阶函数(函数的阶其实就是说参数的个数)转换为低阶函数的方法 。
例如 , 现在有一个 add (int,int) 的函数 , 它实现了将两个数相加的功能 。 假如我们固定集中第一个参数为 5, 则我们会得到一个 add (5,int) 的函数 , 它实现的是将一个数加 5 的功能 。
这有什么意义?
函数降阶可以使得函数变得一致 , 得到了一致的函数之后可以做一些代码上的统一以便优化 。 例如上面使用到的两个表达式:
- Expression ValidateStringRequiredExp
- Expression ValidateStringMinLengthExp
这两个表达式中第二个表达式和第一个表达式之间仅仅区别在第三参数上 。 如果我们使用柯理化固定第三个 int 参数 , 则可以使得两个表达式的签名完全一样 。 这其实和面向对象中的抽象非常类似 。
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{////// Currying///public class X03PropertyValidationTest07{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 isOkProperty = typeof(ValidateResult).GetProperty(nameof(ValidateResult.IsOk));Debug.Assert(isOkProperty != null, nameof(isOkProperty) + " != null");var namePropExp = Expression.Property(inputExp, propertyInfo);var nameNameExp = Expression.Constant(propertyInfo.Name);var requiredMethodExp =Expression.Invoke(CreateValidateStringRequiredExp(),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 isOkProperty = typeof(ValidateResult).GetProperty(nameof(ValidateResult.IsOk));Debug.Assert(isOkProperty != null, nameof(isOkProperty) + " != null");var namePropExp = Expression.Property(inputExp, propertyInfo);var nameNameExp = Expression.Constant(propertyInfo.Name);var requiredMethodExp = Expression.Invoke(CreateValidateStringMinLengthExp(minlengthAttributeLength),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;}}}catch (Exception e){Console.WriteLine(e);throw;}}[Test]public void Run(){// see code in demo repo}private static Expression
推荐阅读
-
刘公岛|“小学生研究癌症获奖”,官方回应:系研究员之子
-
-
石榴花|12种幸运花,你是几月出生,最旺你的花就是那它
-
-
北大首钢医院之窗@他们24小时备战,保障国家队队员健康任务:28天
-
投资者网| 数名核心高管接连出走“无伤大体”?,华润微上市8个月又欲定增50亿
-
-
穿搭|杨紫长得好看衣品更好,穿牛仔连衣裙秀身材,比例让人羡慕
-
捷途|只卖7万左右的中型SUV,空间宽敞实用,还是1.5T
-
-
【别动它我不许】颜值直线飙升,衣品也是美翻了!,有一种整容叫阿拉蕾长大
-
健康骆医师|健康不会远离你,吃青椒有1大禁忌,早知早健康,爱吃青椒的人
-
-
青年|《Haydee》,一款让你烧脑“伤肾”的硬核解密游戏
-
-
红枣■老中医:红枣要少吃,最好不要吃!到底为什么?早知早受益
-
泰光快讯|电动车加装尾箱违规吗?就放个头盔,电动车车主发出紧急提问
-
-
1998年洪水抱着树干的小姑娘 98年洪水7岁女孩抱树9小时
-
7月末|佛山建行:深耕普惠金融,切实扶“微”助“小”