pin*_*mer 16 c# linq-to-entities
假设我有类似的东西
Expression<Func<SomeType, DateTime>> left = x => x.SomeDateProperty;
Expression<Func<SomeType, DateTime>> right = x => dateTimeConstant;
var binaryExpression = Expression.GreaterThan(left, right);
Expression<Func<SomeType, bool>> predicate =
x => x.SomeDateProperty> dateTimeConstant;
Run Code Online (Sandbox Code Playgroud)
1)如何用最后一行的赋值替换最后一行赋值的右手binaryExpression?var predicate = x => binaryExpression;不起作用.
2)right始终是常量,不一定是DateTime.Now.可能是一些更简单的Expression类型?例如,它不依赖于SomeType,它只是一个常量.
3)如果我有GreaterThanas string,是否有办法从这个字符串到同名的方法Expression?通常,如果比较方法的名称是作为a给出的string,我如何从字符串转到实际调用Expression类上具有相同名称的方法?
如果重要的话,它必须与LINQ to Entities一起使用.
Jon*_*Jon 16
1和2:您需要手动构建表达式树来执行此操作,编译器无法提供帮助,因为它只构造完整表示函数的现成表达式.当你想要逐个构建函数时,这没有用.
这是构建所需表达式的一种简单方法:
var argument = Expression.Parameter(typeof(SomeType));
var left = Expression.Property(argument, "SomeDateProperty");
var right = Expression.Constant(DateTime.Now);
var predicate = Expression.Lambda<Func<SomeType, bool>>(
Expression.GreaterThan(left, right),
new[] { argument }
);
Run Code Online (Sandbox Code Playgroud)
您可以将其用于试驾
var param = new SomeType {
SomeDateProperty = DateTime.Now.Add(TimeSpan.FromHours(-1))
};
Console.WriteLine(predicate.Compile()(param)); // "False"
Run Code Online (Sandbox Code Playgroud)
3:由于二进制谓词的可能选择数量很可能非常小,您可以使用字典执行此操作:
var wordToExpression =
new Dictionary<string, Func<Expression, Expression, BinaryExpression>>
{
{ "GreaterThan", Expression.GreaterThan },
// etc
};
Run Code Online (Sandbox Code Playgroud)
然后,Expression.GreaterThan您可以执行类似的操作,而不是在第一个代码段中进行硬编码wordToExpression["GreaterThan"](left, right).
当然,这也可以通过反射的标准方式完成.
使用时GreaterThan,需要指定表达式主体,而不是lambda本身.不幸的是,有一个复杂的问题:x在两个表达式中是不一样的.
在这种特殊情况下,你可以侥幸逃脱,因为第二个表达式不使用x
所以; 您的"1"和"2"应该通过以下方式回答:
var binaryExpression = Expression.GreaterThan(left.Body, right.Body);
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
Run Code Online (Sandbox Code Playgroud)
但是,要在一般情况下处理此问题,您必须重写表达式,以修复参数:
var binaryExpression = Expression.GreaterThan(left.Body,
new SwapVisitor(right.Parameters[0], left.Parameters[0]).Visit(right.Body));
var lambda = Expression.Lambda<Func<SomeType, bool>>(binaryExpression,
left.Parameters);
Run Code Online (Sandbox Code Playgroud)
有:
public class SwapVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public SwapVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression node)
{
return node == from ? to : base.Visit(node);
}
}
Run Code Online (Sandbox Code Playgroud)
为你的"3"; 没有内置的东西; 但你可以使用反射:
string method = "GreaterThan";
var op = typeof(Expression).GetMethod(method,
BindingFlags.Public | BindingFlags.Static,
null, new[] { typeof(Expression), typeof(Expression) }, null);
var rightBody = new SwapVisitor(right.Parameters[0],
left.Parameters[0]).Visit(right.Body);
var exp = (Expression)op.Invoke(null, new object[] { left.Body, rightBody });
var lambda = Expression.Lambda<Func<SomeType, bool>>(exp, left.Parameters);
Run Code Online (Sandbox Code Playgroud)