C# 如何以更通用的方式将运算符应用于表达式
我处理的是动态查询,我不确定如何重构这个示例代码 如果我们想支持更多的操作员/属性,那么梯形图将是巨大的C# 如何以更通用的方式将运算符应用于表达式,c#,generics,lambda,expression,C#,Generics,Lambda,Expression,我处理的是动态查询,我不确定如何重构这个示例代码 如果我们想支持更多的操作员/属性,那么梯形图将是巨大的 var property = "AccountBalance"; var operator = ">"; var value = 5; var query = _context.Users; if (property == "AccountBalance") { if (operator == ">") { query = query.Where
var property = "AccountBalance";
var operator = ">";
var value = 5;
var query = _context.Users;
if (property == "AccountBalance")
{
if (operator == ">")
{
query = query.Where(x => x.AccountBalance > value);
}
}
我希望将其重构为非常通用且可重用的内容,如:
// I simplified comparison here because afaik I'd have to use `CompareTo` due to IComparable
// instead of >, but I don't think it is important right now
public Expression<Func<T, bool>> GetExpression<T, U>(string operator, U value, Func<T, object property) where U : IComparable, T : class
{
switch (operator)
{
case ">":
return property > value;
case "<":
return property < value;
(...)
default:
throw new Exception("undefined operator");
}
}
//我在这里简化了比较,因为由于IComparable,我不得不使用'CompareTo'
//而不是>,但我认为现在这并不重要
公共表达式GetExpression(字符串运算符、U值、Func值;
案例“”,5,新函数(x=>x.AccountBalance));
query=query.Where(表达式);
但我不知道如何将属性传递给该函数
newfunc(x=>x.AccountBalance)
这是伪代码思想您可以将GetExpression
、aFunc
添加为方法的参数,其中T
是要传递其属性之一的对象的类型,U
是属性的类型。然后,当调用方法时,可以传递lambda
例如
var expression=GetExpression(“>”,5,x=>x.AccountBalance);
PS
您必须更改方法签名,如下所示:
public Expression<Func<T, bool>> GetExpression<T, U>
(string operator, U value, Func<T, U> property) where U : IComparable, T : class
公共表达式GetExpression
(字符串运算符,U值,Func属性),其中U:IComparable,T:class
更新
您可以尝试以下方法:
public Expression<Func<T, bool>> GetExpression<T, U>
(string op, U value, Func<T, U> property)
where T: class
where U : IComparable
{
switch (op)
{
case ">":
return p => value.CompareTo(property(p)) > 0;
case "<":
return p => value.CompareTo(property(p)) < 0;
default:
throw new Exception("undefined operator");
}
}
公共表达式GetExpression
(字符串op、U值、Func属性)
T:在哪里上课
其中U:i可比较
{
开关(op)
{
案例“>”:
返回p=>value.CompareTo(属性(p))>0;
case“您可以使用Linq表达式API动态生成表达式
public static Expression<Func<T, bool>> GetExpression<T, U>(string property,
string @operator, U value) where U : IComparable
{
var p = Expression.Parameter(typeof(T), "p");
var member = Expression.PropertyOrField(p, property);
var constant = Expression.Constant(value);
var compareToArgument = Expression.Convert(constant, typeof(object));
var method = typeof(IComparable).GetMethod("CompareTo");
var call = Expression.Call(member, method, compareToArgument);
Expression body = null;
if (@operator == ">")
body = Expression.GreaterThan(call, Expression.Constant(0));
else if (@operator == "<")
body = Expression.LessThan(call, Expression.Constant(0));
// todo: throw if @operator is unknown
var lambda = Expression.Lambda<Func<T, bool>>(body, p);
return lambda;
}
几乎可以工作,但运算符'>'不能应用于'Func'和'U'类型的操作数。
此处:返回属性>值;
是否需要向T:class
添加一些比较接口?
public Expression<Func<T, bool>> GetExpression<T, U>
(string op, U value, Func<T, U> property)
where T: class
where U : IComparable
{
switch (op)
{
case ">":
return p => value.CompareTo(property(p)) > 0;
case "<":
return p => value.CompareTo(property(p)) < 0;
default:
throw new Exception("undefined operator");
}
}
public static Expression<Func<T, bool>> GetExpression<T, U>(string property,
string @operator, U value) where U : IComparable
{
var p = Expression.Parameter(typeof(T), "p");
var member = Expression.PropertyOrField(p, property);
var constant = Expression.Constant(value);
var compareToArgument = Expression.Convert(constant, typeof(object));
var method = typeof(IComparable).GetMethod("CompareTo");
var call = Expression.Call(member, method, compareToArgument);
Expression body = null;
if (@operator == ">")
body = Expression.GreaterThan(call, Expression.Constant(0));
else if (@operator == "<")
body = Expression.LessThan(call, Expression.Constant(0));
// todo: throw if @operator is unknown
var lambda = Expression.Lambda<Func<T, bool>>(body, p);
return lambda;
}
var expression = GetExpression<User, int>("AccountBalance", ">", 5);
query = query.Where(expression);
var p = Expression.Parameter(typeof(T), "p");
var member = Expression.PropertyOrField(p, property);
var constant = Expression.Constant(value);
Expression body = null;
if (@operator == ">=")
body = Expression.GreaterThanOrEqual(member, constant);
if (@operator == "<=")
body = Expression.LessThanOrEqual(member, constant);