如何提取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。如果查询符合规则,则对数据应用查询并返回值。
那么,在对数据应用查询之前,我如何提取查询中使用的属性并测试其中使用的值呢?
您需要使用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/.