C# 从其他两个表达式创建动态表达式lambda(链接表达式)
给定接受标识对象并返回属性的lambda:C# 从其他两个表达式创建动态表达式lambda(链接表达式),c#,dynamic,lambda,runtime,expression,C#,Dynamic,Lambda,Runtime,Expression,给定接受标识对象并返回属性的lambda: Expression<Func<Identification, object>> fx = _ => _.Id; 如何构建一个新的lambda来执行@new(获取标识实例)并将结果传递到fx。我需要@new的结果以某种方式绑定到fx的第一个参数,但我找不到示例 我需要结果是一个表达式,它的类型应该是表达式,它应该将入站参数转换为标识,然后获取Id属性。首先,请注意,如果您适当地键入@new,这会更容易,即: Lambda
Expression<Func<Identification, object>> fx = _ => _.Id;
如何构建一个新的lambda来执行@new
(获取标识实例)并将结果传递到fx
。我需要@new
的结果以某种方式绑定到fx
的第一个参数,但我找不到示例
我需要结果是一个
表达式
,它的类型应该是表达式
,它应该将入站参数转换为标识
,然后获取Id
属性。首先,请注意,如果您适当地键入@new
,这会更容易,即:
LambdaExpression @new = ...
因为这样可以方便地访问@new.Body
和@new.Parameters
;就这样,,
Expression.Invoke在这里可能很有用:
var combinedParam = Expression.Parameter(typeof(object), "o");
var combined = Expression.Lambda<Func<object, object>>(
Expression.Invoke(fx,
Expression.Invoke(@new, combinedParam)), combinedParam);
与:
它的作用是:
- 检查
fx.Body
树,用@new.Body
替换的所有实例(请注意,这将包含对o
参数的引用(也称p
)
- 然后,我们从替换的表达式构建一个新的lambda,重新使用
@new
中的相同参数,这确保了我们注入的值将被正确绑定
使用中的代码,您可以通过一个助手函数很好地简化此过程:
public static class ExpressionHelper {
public static Expression<Func<TFrom, TTo>> Chain<TFrom, TMiddle, TTo>(
this Expression<Func<TFrom, TMiddle>> first,
Expression<Func<TMiddle, TTo>> second
) {
return Expression.Lambda<Func<TFrom, TTo>>(
new SwapVisitor(second.Parameters[0], first.Body).Visit(second.Body),
first.Parameters
);
}
private class SwapVisitor : ExpressionVisitor {
private readonly Expression _from;
private readonly Expression _to;
public SwapVisitor(Expression from, Expression to) {
_from = from;
_to = to;
}
public override Expression Visit(Expression node) {
return node == _from ? _to : base.Visit(node);
}
}
}
公共静态类ExpressionHelper{
公共静态表达式链(
这句话首先,,
表达秒
) {
返回表达式.Lambda(
新建SwapVisitor(第二个参数[0],第一个主体)。访问(第二个主体),
第一,参数
);
}
私有类交换访问者:ExpressionVisitor{
私有只读表达式_from;
私有只读表达式_to;
公共SwapVisitor(表达式from,表达式to){
_from=from;
_to=to;
}
公共重写表达式访问(表达式节点){
return node==\u from?\u to:base.Visit(节点);
}
}
}
现在看那有多干净
var valueSelector = new Expression<Func<MyTable, int>>(o => o.Value);
var intSelector = new Expression<Func<int, bool>>(x => x > 5);
var selector = valueSelector.Chain<MyTable, int, bool>(intSelector);
var-valueSelector=新表达式(o=>o.Value);
var intSelector=新表达式(x=>x>5);
var选择器=valueSelector.Chain(intSelector);
它与实体框架和其他需要干净的表达式的东西一起工作,而这些表达式不试图在其中调用Func
。嗨,我实际上差点就这样做了,但在linqpad中它看起来完全错了。最终的表达式树看起来很可怕,即使经过简化-但它做得很好,谢谢你一次完成这一切,编译器生成一个更整洁的树。(对象p)=>((标识)p).Id你得到的Convert(Convert(p).Id)非常整洁。无论如何,谢谢你的回答。@Jim-你刷新了吗?第二个版本创建的正是o=>Convert(Convert(o).Id)
,而不是o=>Invoke(\u=>Convert(\uid),Invoke(o=>Convert(o,o))
我已经使用了访问者,并生成了新的表达式。非常感谢。
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);
}
}
public static class ExpressionHelper {
public static Expression<Func<TFrom, TTo>> Chain<TFrom, TMiddle, TTo>(
this Expression<Func<TFrom, TMiddle>> first,
Expression<Func<TMiddle, TTo>> second
) {
return Expression.Lambda<Func<TFrom, TTo>>(
new SwapVisitor(second.Parameters[0], first.Body).Visit(second.Body),
first.Parameters
);
}
private class SwapVisitor : ExpressionVisitor {
private readonly Expression _from;
private readonly Expression _to;
public SwapVisitor(Expression from, Expression to) {
_from = from;
_to = to;
}
public override Expression Visit(Expression node) {
return node == _from ? _to : base.Visit(node);
}
}
}
var valueSelector = new Expression<Func<MyTable, int>>(o => o.Value);
var intSelector = new Expression<Func<int, bool>>(x => x > 5);
var selector = valueSelector.Chain<MyTable, int, bool>(intSelector);