如何提取Expression>中使用的属性查询和测试它们的值

本文关键字:属性 查询 测试 result 提取 何提取 Expression Func | 更新日期: 2023-09-27 18:17:56

我需要创建一个函数,在执行某些规则之前对查询进行评估。下面是代码:

public class DataInfo
{
    public int A { get; set; }
    public int B { get; set; }
    public int C { get; set; }
}
static class Program
{
    static void Main()
    {
        var data = new DataInfo()
        {
            A = 10,
            B = 5,
            C = -1
        };
        // the result should be -1
        int result = Calcul<DataInfo>(data, x => x.A / x.B + x.C);
    }
    static int Calcul<T>(T data, Expression<Func<T, int>> query)
    {
        // PSEUDO CODE
        // if one property used in the query have a
        // value of -1 or -2 then return 0
        // {
        //     return 0;
        // }
        // if one property used in the query have a
        // value of 0 AND it is used on the right side of
        // a Divide operation then return -1
        // {
        //     return -1;
        // }
        // if the query respect the rules, apply the query and return the value
        return query.Compile().Invoke(data);
    }
}

在前面的代码中,计算人员想要将A(10)除以B(5),然后加上C(-1)。规则规定,如果查询中使用的一个属性的值为-1或-2,则返回0。所以在这个例子中,返回值应该是-1。如果查询符合规则,则对数据应用查询并返回值。

那么,在对数据应用查询之前,我如何提取查询中使用的属性并测试其中使用的值呢?

如何提取Expression<Func<T、result >>中使用的属性查询和测试它们的值

您需要使用ExpressionVisitor来测试属性值。下面是如何实现该逻辑的示例。

using System;
using System.Linq.Expressions;
using System.Reflection;
namespace WindowsFormsApplication1
{
    static class Program
    {
        [STAThread]
        static void Main()
        {
            // HasDivideByZero - the result should be -1
            int result1 = Calcul<DataInfo>(new DataInfo { A = 10, B = 0, C = 1 }, x => x.A / x.B + x.C);
            // HasNegative - the result should be 0
            int result2 = Calcul<DataInfo>(new DataInfo { A = 10, B = 5, C = -1 }, x => x.A / x.B + x.C);
            // the result should be 3
            int result3 = Calcul<DataInfo>(new DataInfo { A = 10, B = 5, C = 1 }, x => x.A / x.B + x.C);
        }
        static int Calcul<T>(T data, Expression<Func<T, int>> query)
        {
            if (NegativeValueChecker<T>.HasNegative(data, query))
            {
                return 0;
            }
            if (DivideByZeroChecker<T>.HasDivideByZero(data, query))
            {
                return -1;
            }
            return query.Compile().Invoke(data);
        }
    }
    class DivideByZeroChecker<T> : ExpressionVisitor
    {
        private readonly T _data;
        private bool _hasDivideByZero;
        public static bool HasDivideByZero(T data, Expression expression)
        {
            var visitor = new DivideByZeroChecker<T>(data);
            visitor.Visit(expression);
            return visitor._hasDivideByZero;
        }
        public DivideByZeroChecker(T data)
        {
            this._data = data;
        }
        protected override Expression VisitBinary(BinaryExpression node)
        {
            if (!this._hasDivideByZero && node.NodeType == ExpressionType.Divide)
            {
                var rightMemeberExpression = (MemberExpression)node.Right;
                var propertyInfo = (PropertyInfo)rightMemeberExpression.Member;
                var value = Convert.ToInt32(propertyInfo.GetValue(this._data, null));
                this._hasDivideByZero = value == 0;
            }
            return base.VisitBinary(node);
        }
    }
    class NegativeValueChecker<T> : ExpressionVisitor
    {
        private readonly T _data;
        public bool _hasNegative;
        public static bool HasNegative(T data, Expression expression)
        {
            var visitor = new NegativeValueChecker<T>(data);
            visitor.Visit(expression);
            return visitor._hasNegative;
        }
        public NegativeValueChecker(T data)
        {
            this._data = data;
        }
        protected override Expression VisitMember(MemberExpression node)
        {
            if (!this._hasNegative)
            {
                var propertyInfo = (PropertyInfo)node.Member;
                var value = Convert.ToInt32(propertyInfo.GetValue(this._data, null));
                this._hasNegative = value < 0;
            }
            return base.VisitMember(node);
        }
    }
    class DataInfo
    {
        public int A { get; set; }
        public int B { get; set; }
        public int C { get; set; }
    }
}

查看Moq的源代码 - http://code.google.com/p/moq/.