如何将 Expression<Func<T>> 和 Expression<Func<T,float>> 合并为 Expression<Func<float>>?
How to combine Expression<Func<T>> and Expression<Func<T,float>> to Expression<Func<float>>?
我正在尝试结合 expr1
和 expr2
生成 Expression<Func<float>>
:
var expr1 = (Expression<Func<ColorComponent>>)(() => _modelRgb.R);
var expr2 = (Expression<Func<ColorComponent, float>>)(s => s.Value);
var expr3 = Expression.Lambda(expr1, expr2.Parameters);
虽然对 expr3
的调用有效,但它的 .Body
属性 不能转换为 MemberExpression
。
这里是手工制作的表达式的调试字符串和expr3
,显然它们是不同的:
"() => (ColorPicker.ColorPickerWindow2)._modelRgb.R.Value"
"s => () => (ColorPicker.ColorPickerWindow2)._modelRgb.R"
问题是:
使 expr3
成为 MemberExpression
而不是 LambdaExpression
的正确方法是什么?
我想要达到的目标:
我想将像 () => _modelRgb.R
这样指向 ColorComponent
的表达式传递给一个方法,在这个方法中我想为它的一些成员构建大量表达式。
您在这里基本上要做的是组合两个表达式。 是一个展示如何做到这一点的解决方案,尽管它需要一些调整以使第一个表达式没有参数,而不是一个参数。
改编后的 Compose
方法如下所示:
public static Expression<Func<TResult>> Compose<TSource, TResult>(
this Expression<Func<TSource>> first,
Expression<Func<TSource, TResult>> second)
{
return Expression.Lambda<Func<TResult>>(
second.Body.Replace(second.Parameters[0], first.Body));
}
这将使用与链接问题相同的 Replace
方法,无需任何改编:
public class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression ex)
{
if (ex == from) return to;
else return base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
通过使用上述方法概括代码,您可以确保代码无论任何一个表达式的内容如何,而不是编写一个方法来假设什么可以或不能在任何一个表达式中,也不能以不同的方式处理一堆不同的情况。
我正在尝试结合 expr1
和 expr2
生成 Expression<Func<float>>
:
var expr1 = (Expression<Func<ColorComponent>>)(() => _modelRgb.R);
var expr2 = (Expression<Func<ColorComponent, float>>)(s => s.Value);
var expr3 = Expression.Lambda(expr1, expr2.Parameters);
虽然对 expr3
的调用有效,但它的 .Body
属性 不能转换为 MemberExpression
。
这里是手工制作的表达式的调试字符串和expr3
,显然它们是不同的:
"() => (ColorPicker.ColorPickerWindow2)._modelRgb.R.Value"
"s => () => (ColorPicker.ColorPickerWindow2)._modelRgb.R"
问题是:
使 expr3
成为 MemberExpression
而不是 LambdaExpression
的正确方法是什么?
我想要达到的目标:
我想将像 () => _modelRgb.R
这样指向 ColorComponent
的表达式传递给一个方法,在这个方法中我想为它的一些成员构建大量表达式。
您在这里基本上要做的是组合两个表达式。
改编后的 Compose
方法如下所示:
public static Expression<Func<TResult>> Compose<TSource, TResult>(
this Expression<Func<TSource>> first,
Expression<Func<TSource, TResult>> second)
{
return Expression.Lambda<Func<TResult>>(
second.Body.Replace(second.Parameters[0], first.Body));
}
这将使用与链接问题相同的 Replace
方法,无需任何改编:
public class ReplaceVisitor : ExpressionVisitor
{
private readonly Expression from, to;
public ReplaceVisitor(Expression from, Expression to)
{
this.from = from;
this.to = to;
}
public override Expression Visit(Expression ex)
{
if (ex == from) return to;
else return base.Visit(ex);
}
}
public static Expression Replace(this Expression ex,
Expression from,
Expression to)
{
return new ReplaceVisitor(from, to).Visit(ex);
}
通过使用上述方法概括代码,您可以确保代码无论任何一个表达式的内容如何,而不是编写一个方法来假设什么可以或不能在任何一个表达式中,也不能以不同的方式处理一堆不同的情况。