加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – 如何评估ExpressionVisitor中的表达式?

发布时间:2020-12-16 01:50:28 所属栏目:百科 来源:网络整理
导读:我需要在执行它之前使用ExpressionVisitor来分析Expression.根据我的需要,我需要评估Divide表达式的正确部分,但我不知道该怎么做.这是我的示例代码: internal class RulesChecker : ExpressionVisitor{ private readonly object data; public RulesChecker(
我需要在执行它之前使用ExpressionVisitor来分析Expression.根据我的需要,我需要评估Divide表达式的正确部分,但我不知道该怎么做.这是我的示例代码:

internal class RulesChecker : ExpressionVisitor
{
    private readonly object data;

    public RulesChecker(object data)
    {
        this.data = data;
    }

    protected override Expression VisitBinary(BinaryExpression node)
    {
        if (node.NodeType == ExpressionType.Divide)
        {
            var rightExpression = node.Right;

            // compile the right expression and get his value            
        }

        return base.VisitBinary(node);
    }
}

假设我有这个代码来评估:

Expression<Func<DataInfo,decimal?>> expression = x => x.A / (x.B + x.C);
var rulesChecker = new RulesChecker(data);
rulesChecker.Visit(expression);

在VisitBinary函数中,我将收到一个节点,该节点将包含除法运算的左右部分.我的问题是,我如何评估我将在操作的正确部分获得的价值?

解决方法

我认为这个问题最困难的部分是处理变量.所以我首先要替换常量变量.之后,您只需执行并更新Expression.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;

namespace WindowsFormsApplication1
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            var value1 = 1;
            var value2 = 2;
            var value3 = new { MyValue = 3 };
            var data = new DataInfo { A = 10,B = 1,C = -1 };

            Expression<Func<DataInfo,decimal?>> expression = x => x.A / (x.B + x.C) + (value1 + value2) + value3.MyValue;

            // create a list of variables that will be used when evaluating the expression
            var variables = new Dictionary<Type,object>();

            // add the root object
            variables.Add(data.GetType(),data);

            // find variables that are referenced in the expression
            var finder = new VariablesFinder(variables);
            finder.Visit(expression);

            // replace variables with ConstantExpressions
            var visitor = new VariableReplacer(variables);
            var newExpression = visitor.Visit(expression);

            var rulesChecker = new RulesChecker();
            var checkedExpression = rulesChecker.Visit(newExpression);
        }
    }

    internal class RulesChecker : ExpressionVisitor
    {
        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (node.NodeType == ExpressionType.Divide)
            {
                var rightBinaryExpression = node.Right as BinaryExpression;

                if (rightBinaryExpression != null)
                {
                    node = node.Update(node.Left,node.Conversion,this.Execute(rightBinaryExpression));
                }
            }

            return base.VisitBinary(node);
        }

        private Expression Execute(BinaryExpression node)
        {
            var lambda = Expression.Lambda(node);
            dynamic func = lambda.Compile();
            var result = func();

            return Expression.Constant(result,result.GetType());
        }
    }

    internal class VariableReplacer : ExpressionVisitor
    {
        private readonly Dictionary<Type,object> _variables;

        public VariableReplacer(Dictionary<Type,object> variables)
        {
            this._variables = variables;
        }

        protected override Expression VisitMember(MemberExpression node)
        {
            return this.HandleProperty(node) ??
                   this.HandleField(node) ??
                   node;
        }

        private Expression HandleField(MemberExpression memberExpression)
        {
            var fieldInfo = memberExpression.Member as FieldInfo;

            if (fieldInfo != null)
            {
                var value = fieldInfo.GetValue(this.GetVarialbe(fieldInfo));

                return Expression.Constant(value,fieldInfo.FieldType);
            }

            return null;
        }

        private Expression HandleProperty(MemberExpression memberExpression)
        {
            var propertyInfo = memberExpression.Member as PropertyInfo;

            if (propertyInfo != null)
            {
                var value = propertyInfo.GetValue(this.GetVarialbe(propertyInfo),null);

                return Expression.Constant(value,propertyInfo.PropertyType);
            }

            return null;
        }

        private object GetVarialbe(MemberInfo memberInfo)
        {
            return this._variables[memberInfo.DeclaringType];
        }
    }

    internal class VariablesFinder : ExpressionVisitor
    {
        private readonly Dictionary<Type,object> _variables;

        public VariablesFinder(Dictionary<Type,object> variables)
        {
            this._variables = variables;
        }

        protected override Expression VisitConstant(ConstantExpression node)
        {
            this.AddVariable(node.Type,node.Value);

            return base.VisitConstant(node);
        }

        private void AddVariable(Type type,object value)
        {
            if (type.IsPrimitive)
            {
                return;
            }

            if (this._variables.Keys.Contains(type))
            {
                return;
            }

            this._variables.Add(type,value);

            var fields = type.GetFields().Where(x => !x.FieldType.IsPrimitive).ToList();

            foreach (var field in fields)
            {
                this.AddVariable(field.FieldType,field.GetValue(value));
            }
        }
    }

    class DataInfo
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
        public int D;
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读