当前位置: 首页 > 编程语言 > C#

如何计算ExpressionVisitor中的表达式?分享

时间:2023-04-10 20:32:10 C#

如何在ExpressionVisitor中计算表达式?在执行Expression之前,我需要使用ExpressionVisitor对其进行分析。根据我的需要,我需要评估Divide表达式的正确部分,但我不知道该怎么做。这是我的示例代码:internalclassRulesChecker:ExpressionVisitor{privatereadonlyobjectdata;publicRulesChecker(objectdata){this.data=data;}protectedoverrideExpressionVisitBinary(BinaryExpressionnode){if(node.NodeType==ExpressionType.Divide){varrightExpression=node.Right;//编译正确的表达式并获取他的值}returnbase.VisitBinary(node);假设我有这段代码要评估:Expressionexpression=x=>xA/(xB+xC);varrulesChecker=newRulesChecker(数据);rulesChecker.Visit(表达式);在VisitBinary函数中,我将收到一个节点,该节点将包含除法运算的左右部分。我的问题是,如何评估我将在操作的正确部分获得的价值?我认为这个问题最难的部分是处理变量。所以我首先要替换常量变量。之后,您只需执行并更新Expression。使用系统;使用System.Collections.Generic;使用System.Linq;使用System.Linq.Expressions;使用System.Reflection;namespaceWindowsFormsApplication1{staticclassProgram{[STAThread]staticvoidMain(){varvalue1=1;变量值2=2;varvalue3=new{MyValue=3};vardata=newDataInfo{A=10,B=1,C=-1};表达式>表达式=x=>xA/(xB+xC)+(value1+value2)+value3.MyValue;//创建将在评估表达式时使用的变量列表varvariables=newDictionary();//添加根对象variables.Add(data.GetType(),data);//查找表达式中引用的变量varfinder=newVariablesFinder(variables);finder.Visit(表达式);//用常量表达式替换变量varvisitor=newVariableReplacer(variables);varnewExpression=visitor.Visit(expression);varrulesChecker=newRulesChecker();varcheckedExpression=rulesChecker.Visit(newExpression);}}内部类RulesChecker:ExpressionVisitor{protectedoverrideExpressionVisitBinary(BinaryExpressionnode){if(node.NodeType==ExpressionType.Divide){varrightBinaryExpression=node.RightasBinaryExpression;if(rightBinaryExpression!=null){node=node.Update(node.Left,node.Conversion,this.Execute(rightBinaryExpression));}}返回base.VisitBinary(node);}privateExpressionExecute(BinaryExpressionnode){varlambda=Expression.Lambda(node);动态函数=lambda.Compile();变量结果=函数();返回Expression.Constant(result,result.GetType());}}内部类VariableReplacer:ExpressionVisitor{privatereadonlyDictionary_variables;publicVariableReplacer(Dictionaryvariables){this._variables=variables;}protectedoverrideExpressionVisitMember(MemberExpressionnode){returnthis.HandleProperty(node)??这个.HandleField(节点)??节点;}privateExpressionHandleField(MemberExpressionmemberExpression){varfieldInfo=memberExpression.MemberasFieldInfo;if(fieldInfo!=null){varvalue=fieldInfo.GetValue(this.GetVarialbe(fieldInfo));返回Expression.Constant(value,fieldInfo.FieldType);}返回空值;}privateExpressionHandleProperty(MemberExpressionmemberExpression){varpropertyInfo=memberExpression.MemberasPropertyInfo;if(propertyInfo!=null){varvalue=propertyInfo.GetValue(this.GetVarialbe(propertyInfo),null);返回Expression.Constant(value,propertyInfo.PropertyType);}返回空值;}privateobjectGetVarialbe(MemberInfomemberInfo){returnthis._variables[memberInfo.DeclaringType];}}内部类VariablesFinder:ExpressionVisitor{privatereadonlyDictionary_variables;publicVariablesFinder(字典变量){this._variables=variables;}protectedoverrideExpressionVisitConstant(ConstantExpressionnode){this.AddVariable(node.Type,node.Value);返回base.VisitConstant(node);}私人电话idAddVariable(Type类型,对象值){if(type.IsPrimitive){return;}if(this._variables.Keys.Contains(type)){返回;}this._variables.Add(type,value);varfields=type.GetFields().Where(x=>!x.FieldType.IsPrimitive).ToList();foreach(varfieldinfields){this.AddVariable(field.FieldType,field.GetValue(value));}}}classDataInfo{publicintA{get;放;}publicintB{得到;放;}publicintC{得到;放;}公共诠释D;并传递):protectedobjectEvaluateExpression(Expressionexpression){varlambda=Expression.Lambda(expression);varcompiled=lambda.Compile();varvalue=compiled.DynamicInvoke(null);返回值;但是,在你的情况下,这将不起作用,因为你试图评估的表达式取决于x,除非你给它一个具体的值,否则无法评估它,正如Wiktor所建议的给参数赋值,需要修改方法:varcompiled=lambda.Compile();返回compiled.DynamicInvoke(5);//这里的5是实参值。将其更改为您想要的任何内容}但是,此版本的方法必须将ExpressionParameter对象作为参数,该对象表示表达式中的x,以便它知道如何处理传递给DynamicInvoke()值的值。为了获得正确的ExpressionParameter对象,您需要访问根表达式,而不是其中一个节点,所以我想在访问者中执行此操作会很尴尬。如果我理解正确,您希望将访问表达式的结果返回到修改后的表达式树中,该表达式树以某种方式评估了分区的右侧。您将使用BinaryExpression的Update方法将正确的节点替换为您的值://编译正确的表达式并获取他的值varnewRightExpression=Evaluate(rightExpression);返回node.Update(node.Left,node.Conversion,newRightExpression);}返回base.VisitBinary(node);这段代码中,newRightExpression需要继承自Expression类型。如果右节点的计算结果为double值,则需要将其包装在ConstantExpression中:doublerightValue=EvaluateToDouble(rightExpression);varnewRightExpression=Expression.Constant(rightValue,typeof(double));我认为@w0lf是正确的道路。要从访问者那里获取参数,您需要重写VisitLambda。最好的方法是重写访问者的每个可用方法并将参数传递给您的所有方法。另一种方法是保存最新的参数。事实上,参数数组在整个lambda表达式中都是相同的。下面是一段代码,将除法运算的右侧乘以2并将其替换为原始表达式,假设右侧和左侧均为双精度类型。以上就是C#学习教程:ExpressionVisitor中的表达式如何求值?所有分享的内容,如果对你有用,需要了解更多C#学习教程,希望大家多多关注—classProgram{staticvoidMain(string[]args){Expression>abc=v=>1.0d*v.Ticks/(v.Month+v.Minute);MyExpressionVisitormev=newMyExpressionVisitor(DateTime.Now);varret=mev.Visit(abc);}}内部类MyExpressionVisitor:ExpressionVisitor{IEnumerable_parameters=null;对象_parameterValue=null;publicMyExpressionVisitor(objectvalueOfParameter){_parameterValue=valueOfParameter;}protectedoverrideExpressionVisitLambda(Expressionnode){_parameters=node.Parameters;返回base.VisitLambda(节点);!=null){//评估权利node.varvalue=EvaluateExpression(node.Right,_parameters.ToArray(),_parameterValue);//将值替换为2*value.varnewRight=Expression.Constant(value*2);varret=node.Update(node.Left,node.Conv版本,newRight);返还;}返回base.VisitBinary(node);}protecteddoubleEvaluateExpression(Expressionexpression,ParameterExpression[]parameters,objectparameterValue){varlambda=Expression.Lambda(expression,parameters);varcompiled=lambda.Compile();varvalue=compiled.DynamicInvoke(parameterValue);返回Convert.ToDouble(值);}}本文收集自网络,不代表立场。如涉及侵权,请点击右侧联系管理员删除。来源: