(转载请删除括号里的内容)
需求的这样的:
业务想让用户输入任意表达式进行计算假如成立则允许操作
表达式组成:
常量与特殊变量进行任意加减乘除有特殊值比较大小
表达式实例:
- L+2*W<200
- H>50
- 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
{
//不是第一次进入不可能是null
expression = 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();//表达式编译为委托
}
#endregion
return func.Invoke(model);
}
}
---------------------
作者:樱桃丶老丸子
来源:CSDN
原文:https://blog.csdn.net/m0_48365841/article/details/121380411
版权声明:本文为作者原创文章,转载请附上博文链接!