Expression实现 字符串转表达式 自定义计算体积参数

这篇文章是为了解决我工作中的一个需求而写,希望能帮到有需要的人

需求的这样的:
业务想让用户输入任意表达式进行计算假如成立则允许操作

表达式组成:
常量与特殊变量进行任意加减乘除有特殊值比较大小

表达式实例:

  1. L+2*W<200
  2. H>50
  3. L/W+H*20-10>=100

调用方法

ExpressionVolume expressionVolume = new ExpressionVolume();//计算表达式的值Console.WriteLine(expressionVolume.InvokeOperator("L+10+2*W/10+H+200-800/20+L+W>=200", new ExpressionVolume.VolumeClass(10, 50, 100)));Console.WriteLine(expressionVolume.InvokeOperator("L+10+2*W/10+H+200-800/4+L+H/W>=200", new ExpressionVolume.VolumeClass(1, 1, 1)));Console.WriteLine((decimal)10 + (decimal)10 + (decimal)2 * (decimal)50 / (decimal)10 + (decimal)100 + (decimal)200 - (decimal)800 / (decimal)20 + (decimal)10 + (decimal)50);Console.WriteLine((decimal)1 + (decimal)10 + (decimal)2 * (decimal)1 / (decimal)10 + (decimal)1 + (decimal)200 - (decimal)800 / (decimal)4 + (decimal)1 + (decimal)1 / (decimal)1);//比较表达式是否成立Console.WriteLine(expressionVolume.InvokeEqual("L+10+2*W/10+H+200-800/20+L+W<200", new ExpressionVolume.VolumeClass(10, 50, 100)));Console.WriteLine(expressionVolume.InvokeEqual("L+10+2*W/10+H+200-800/4+L+H/W<200", new ExpressionVolume.VolumeClass(1, 1, 1)));//验证表达式是否成立(!=-1表示成立)Console.WriteLine(expressionVolume.Verification("L+10+2*W/10+H+200-800/20+L+W<200")); Console.WriteLine(expressionVolume.Verification("W+10+2*W/10+H+200-800/20+W+W<200"));Console.WriteLine(expressionVolume.Verification("L+2+2*-W/10+H+200-800/20+L+W<=200"));Console.WriteLine(expressionVolume.Verification("-L+33+2/*W/10+H+200-800/20+L+W>=200"));Console.WriteLine(expressionVolume.Verification("L+10-+2*W/10+H+200-800/20+L+W"));Console.WriteLine(expressionVolume.Verification("L++10+2*W/10+H+200-800/20+L+W"));expressionVolume.Verification("L+10+2*W/10+HL+200-800/20+L+W<200");

代码实现

/// <summary>/// 计算体积参数/// </summary>public class ExpressionVolume{#region 私有类/// <summary>/// 体积参数类/// </summary>public class VolumeClass{/// <summary>/// 不可以去掉/// Expression合成方法时需要支持无参实例化/// </summary>public VolumeClass(){}/// <summary>/// 实例化/// </summary>/// <param name="Long">长</param>/// <param name="Width">宽</param>/// <param name="Height">高</param>public VolumeClass(decimal? Long, decimal? Width, decimal? Height, decimal? Wt_Weight = null){this.L = Long ?? 0;this.W = Width ?? 0;this.H = Height ?? 0;this.Wt_Weight = Wt_Weight ?? 0;}/// <summary>/// 长/// </summary>/// <remarks>/// 不能随意改变字段名/// Expression合成方法时需要/// </remarks>public decimal L { get; set; }/// <summary>/// 宽/// </summary>/// <remarks>/// 不能随意改变字段名/// Expression合成方法时需要/// </remarks>public decimal W { get; set; }/// <summary>/// 高/// </summary>/// <remarks>/// 不能随意改变字段名/// Expression合成方法时需要/// </remarks>public decimal H { get; set; }/// <summary>/// 重量/// </summary>public decimal Wt_Weight { get; set; }}#endregion/// <summary>/// 线程锁,防止缓存键值对时异常/// </summary>private readonly static object Lock = new object { };/// <summary>/// 缓存表达式(比较)/// </summary>private readonly static Dictionary<string, Func<VolumeClass, bool>> DicEqual = new Dictionary<string, Func<VolumeClass, bool>>();/// <summary>/// 比较表达式是否成立/// </summary>/// <param name="expressionString">表达式</param>/// <param name="volume">体积参数</param>/// <returns></returns>public bool InvokeEqual(string expressionString, VolumeClass volume){if (DicEqual.ContainsKey(expressionString)){return DicEqual[expressionString].Invoke(volume);}var strs = expressionString.Split('>', '<');if (strs.Length != 2){DicEqual.Add(expressionString, t => false);return false;}//定义体积参数ParameterExpression parameterExpression = Expression.Parameter(typeof(VolumeClass), "volume");Expression expression = GetExpression(strs[0], parameterExpression);//是否大于bool IsGreaterThan = expressionString.Contains('>');//是否允许相等bool IsEqual = strs[1].StartsWith("=");strs[1] = strs[1].TrimStart('=');decimal Equal = decimal.Parse(strs[1]);if (IsGreaterThan){if (IsEqual){expression = Expression.GreaterThanOrEqual(expression, Expression.Constant(Equal, typeof(decimal)));}else{expression = Expression.GreaterThan(expression, Expression.Constant(Equal, typeof(decimal)));}}else{if (IsEqual){expression = Expression.LessThanOrEqual(expression, Expression.Constant(Equal, typeof(decimal)));}else{expression = Expression.LessThan(expression, Expression.Constant(Equal, typeof(decimal)));}}//获得Lambda表达式Expression<Func<VolumeClass, bool>> Lambda = Expression.Lambda<Func<VolumeClass, bool>>(expression, parameterExpression);//生成对应的委托var func = Lambda.Compile();//防止并发导致异常if (!DicEqual.ContainsKey(expressionString)){lock (Lock){if (!DicEqual.ContainsKey(expressionString)){//缓存委托DicEqual.Add(expressionString, func);}}}return func.Invoke(volume);}/// <summary>/// 缓存表达式(计算值)/// </summary>private readonly static Dictionary<string, Func<VolumeClass, decimal>> DicOperator = new Dictionary<string, Func<VolumeClass, decimal>>();/// <summary>/// 得到表达式左侧的值/// </summary>/// <param name="expressionString">表达式</param>/// <param name="volume">体积参数</param>/// <returns></returns>public decimal InvokeOperator(string expressionString, VolumeClass volume){if (DicOperator.ContainsKey(expressionString)){return DicOperator[expressionString].Invoke(volume);}var strs = expressionString.Split('>', '<');if (strs.Length != 2){DicOperator.Add(expressionString, t => -1);return -1;}//定义体积参数ParameterExpression parameterExpression = Expression.Parameter(typeof(VolumeClass), "volume");System.Linq.Expressions.Expression expression = GetExpression(strs[0], parameterExpression);//获得Lambda表达式Expression<Func<VolumeClass, decimal>> Lambda = Expression.Lambda<Func<VolumeClass, decimal>>(expression, parameterExpression);//生成对应的委托var func = Lambda.Compile();//防止并发导致异常if (!DicOperator.ContainsKey(expressionString)){lock (Lock){if (!DicOperator.ContainsKey(expressionString)){//缓存委托DicOperator.Add(expressionString, func);}}}return func.Invoke(volume);}/// <summary>/// 验证表达式/// </summary>/// <param name="expressionString">表达式</param>/// <returns></returns>public decimal Verification(string expressionString){var strs = expressionString.Split('>', '<');if (strs.Length != 2){DicOperator.Add(expressionString, t => -1);return -1;}if (string.IsNullOrEmpty(strs[1])){return -1;}//定义体积参数ParameterExpression parameterExpression = Expression.Parameter(typeof(VolumeClass), "volume");System.Linq.Expressions.Expression expression = GetExpression(strs[0], parameterExpression);//获得Lambda表达式Expression<Func<VolumeClass, decimal>> Lambda = Expression.Lambda<Func<VolumeClass, decimal>>(expression, parameterExpression);//生成对应的委托var func = Lambda.Compile();return func.Invoke(new VolumeClass(1, 1, 1));}#region 私有方法/// <summary>/// 生成公共表达式/// </summary>/// <param name="str"></param>/// <param name="parameterExpression">定义体积参数</param>/// <returns></returns>private System.Linq.Expressions.Expression GetExpression(string str, ParameterExpression parameterExpression){if (str.StartsWith("+") || str.StartsWith("-") || str.StartsWith("*") || str.StartsWith("/")){throw new Exception("表达式不能已符号开头");}Expression expression = null;foreach (var Add in str.Split('+')){if (Add.Contains('-')){//假如是第一次进入则表示还是+bool IsFirst = true;foreach (var Subtract in Add.Split('-')){Expression _expression = null;if (Subtract.Contains('*')){_expression = MultiplyAction(Subtract, parameterExpression);}else if (Subtract.Contains('/')){_expression = DivideAction(Subtract, parameterExpression);}else{_expression = GetPropertyOrConstant(Subtract, parameterExpression);}if (IsFirst){expression = expression == null ? _expression : Expression.Add(expression, _expression);}else{//不是第一次进入不可能是nullexpression = Expression.Subtract(expression, _expression);}IsFirst = false;}}else if (Add.Contains('*')){Expression _expression = MultiplyAction(Add, parameterExpression);expression = expression == null ? _expression : Expression.Add(expression, _expression);}else if (Add.Contains('/')){Expression _expression = DivideAction(Add, parameterExpression);expression = expression == null ? _expression : Expression.Add(expression, _expression);}else{//拼接+Expression _expression = GetPropertyOrConstant(Add, parameterExpression);expression = expression == null ? _expression : Expression.Add(expression, _expression);}}return expression;}/// <summary>/// 乘/// </summary>/// <param name="str"></param>private System.Linq.Expressions.Expression MultiplyAction(string str, ParameterExpression parameterExpression){List<Expression> list = new List<Expression>();foreach (var Multiply in str.Split('*')){list.Add(Multiply.Contains('/') ? DivideAction(Multiply, parameterExpression) : GetPropertyOrConstant(Multiply, parameterExpression));}Expression MultiplyExpression = list[0];for (int i = 1; i < list.Count; i++){MultiplyExpression = Expression.Multiply(MultiplyExpression, list[i]);}return MultiplyExpression;}/// <summary>/// 除/// </summary>/// <param name="str"></param>private System.Linq.Expressions.Expression DivideAction(string str, ParameterExpression parameterExpression){string[] strs = str.Split('/');return Expression.Divide(GetPropertyOrConstant(strs[0], parameterExpression), GetPropertyOrConstant(strs[1], parameterExpression));}/// <summary>/// 获取属性或常量/// </summary>/// <param name="value">字符串</param>/// <param name="parameterExpression">变量参数</param>/// <returns></returns>private System.Linq.Expressions.Expression GetPropertyOrConstant(string value, ParameterExpression parameterExpression){if (string.IsNullOrEmpty(value)){throw new Exception("符号不能相连");}Expression expression = null;if (value == "L" || value == "W" || value == "H"){//读取变量的属性expression = Expression.Property(parameterExpression, value);}else{try{expression = Expression.Constant(decimal.Parse(value), typeof(decimal));}catch (Exception){throw new Exception("长宽高不能相连");}}return expression;}#endregion}

实体类赋值(与本文章无关内容放到这边方便复制)

/// <summary>/// 不支持DataRow  泛型缓存/// </summary>/// <typeparam name="Tout">返回类型</typeparam>/// <typeparam name="Tin">接受类型</typeparam>public class ModelCopy<Tin, Tout>{private static Func<Tin, Tout> func { get; set; }//静态缓存字段/// <summary>/// 赋值/// </summary>/// <param name="model"></param>/// <returns></returns>public static Tout Invoke(Tin model)//公共方法,返回Map到的对象实例{#region 为Func赋值if (func == null){Type inType = typeof(Tin);Type outType = typeof(Tout);ParameterExpression parameterExpression = Expression.Parameter(inType, "tIn");//准备一个参数表达式List<MemberBinding> memberBindings = new List<MemberBinding>();//准备属性绑定的集合foreach (var item in outType.GetProperties())//遍历所有的属性{PropertyInfo propertyInfo = inType.GetProperty(item.Name);//获取到传入实例中的属性if (propertyInfo == null)continue;MemberExpression memberExpression = Expression.Property(parameterExpression, propertyInfo);//准备一个成员的表达式MemberBinding memberBinding = Expression.Bind(item, memberExpression);//绑定memberBindings.Add(memberBinding);//添加到列表}//字段//foreach (var item in outType.GetFields())//{//    FieldInfo fieldInfo = inType.GetField(item.Name);//    if (fieldInfo == null)//        continue;//    MemberExpression memberExpression = Expression.Field(parameterExpression, fieldInfo);//    MemberBinding memberBinding = Expression.Bind(item, memberExpression);//    memberBindings.Add(memberBinding);//}MemberInitExpression memberInitExpression = Expression.MemberInit(Expression.New(outType), memberBindings.ToArray());Expression<Func<Tin, Tout>> lambdaExpression = Expression.Lambda<Func<Tin, Tout>>(memberInitExpression, new ParameterExpression[] { parameterExpression });func = lambdaExpression.Compile();//表达式编译为委托}#endregionreturn func.Invoke(model);}}

C#通过Expression实现 字符串转表达式 自定义计算体积参数相关推荐

  1. java 计算运算表达式_java字符串运算表达式的计算

    一道面试题,如何不拆分字符串,对字符串表达式进行计算,形如:String str = "5+2-1" 1.[代码][Java]代码 import java.math.BigDeci ...

  2. R语言parse函数、deparse函数、expression函数实现字符串和表达式的转换实战

    R语言parse函数.deparse函数.expression函数实现字符串和表达式的转换实战 目录 R语言parse函数.deparse函数.expression函数实现字符串和表达式的转换实战

  3. python算法——字符串表达式的计算

    preface:最近有个面试,被要求给出一个字符串表达式,计算出结果.本以为是见到过的,想着用一个栈,然后被面试官打断说你这样是有问题的,然后想了说用树,又被打断说是有问题的,再仔细想想.结果还是没整 ...

  4. 字符串算术表达式求值-简单计算器实现(栈)-数据结构和算法(Java)

    1 字符串算术表达式分类 字符串算术表达式分为前缀表达式.中缀表达式和后缀表达式.其中前缀表达式又称波兰表达式,后缀表达式基于前缀表达式,又称逆波兰表达式.下面给出百度百科关于几种表达式的定义: 前缀 ...

  5. 【C 语言】二级指针案例 ( 字符串切割 | 返回 自定义二级指针 作为结果 | 每个 一级指针 指向不同大小内存 | 精准分配每个 一级指针 指向的内存大小 )

    文章目录 一.二级指针案例 ( 返回自定义二级指针 | 精准控制内存大小 ) 二.完整代码示例 一.二级指针案例 ( 返回自定义二级指针 | 精准控制内存大小 ) 博客 [C 语言]二级指针案例 ( ...

  6. python笔记5 - 字符串格式化表达式,while语句嵌套,for循环,break,continue,死循环

    2017/9/29 字符串格式化表达式,while语句嵌套,for循环,break,continue,死循环 ============================================= ...

  7. php二元表达式,PHP 计算字符串表达式(二) | 剑花烟雨江南

    由于eval()在安全性上存在问题,因此需考虑使用其余办法解决字符串表达式的计算.在数据结构中,栈(stack)是一种只能在一端进行插入和删除操作的特殊线性表.它按照先进后出的原则存储数据,先进入的数 ...

  8. MySQL连接字符串,可以自定义连接时字符集编码

    MySQL连接字符串,可以自定义连接时字符集编码 jdbc:mysql://localhost:3306/${database}?useUnicode=true&characterEncodi ...

  9. Expression 核心操作符、表达式、操作方法

    一.Expression中的操作运算符   成员名称 说明   Add 加法运算,如 a + b, ,不进行溢出检查,针对数值操作数.   AddAssign 加法复合赋值运算,如 (a += b), ...

最新文章

  1. android 动画x轴旋转,Android Roate3dAnimation实现围绕y轴竖直方向或者绕x轴方向旋转的3d动画效果...
  2. 哈希(Hash)算法是一种单向密码体制(它是一个从明文到密文的不可逆的映射只有加密过程没有解密过程)
  3. 防护很重要!教你教你认识和检验安防产品的IP防护等级
  4. android应用可以访问/dev下设备节点
  5. 算法—2,记一个自己的算法题 计算数字k在0到n中的出现的次数,k可能是0~9的一个值
  6. dotnetcore+vue+elementUI 前后端分离 三(前端篇)
  7. python按比例生成数据组_基于python中的一个值生成“正态分布”数据
  8. 机器学习的几种主要学习方法
  9. django mysql secure_auth_MySQL8.0的用户密码加密方式Django2.1兼容。
  10. Linux内核模块(一)
  11. win10应用商店打不开_最冷清的应用商店?为何Win10商店无人问津
  12. VFB组件:Scintilla控件(代码编辑器)
  13. android 打开方式,Android默认打开开发者模式方式
  14. 银联刷卡POS机冲正
  15. Python 获取Windows关机消息
  16. 深度学习中常见的打标签工具和数据集集合
  17. [附源码]计算机毕业设计springboot公益组织登记与查询系统论文
  18. CWND和HWND之间的关系和转换 和获取方法
  19. 世界电信日| 谈谈电信行业缘何牵线云计算?
  20. 为什么微软拼音会莫名其妙变繁体以及Junit的一些笔记

热门文章

  1. java比较两个list是否相同_Java判断两个List是否相同
  2. 300PLCmpi转以太网通过MPI-ETH-XD1.0在气动系统中的应用
  3. kaggle住房预测项目——第2部分(bagging)
  4. notify()方法、notifyAll()方法和wait()方法 详解
  5. 计算机国家二级通过率多少?
  6. 在 Visual Basic .NET 中使用存储过程
  7. 关于用硬盘安装工具Win6Ins_v1.2.0.62安装时提示缺少hildr.mbr文件的解决办法
  8. 绿色环保作为经济长线主题,MOVE PROTOCOL运动APP来助力
  9. 国外旋转楼梯sketchup建模教程h
  10. C/C++ ImGUI劫持Dx9绘制窗体