如果Expression
包含X
Expression
,是否可以创建从Y
收到X
类型的Y
来接收public class Y {
public int Something { get; set; }
}
public class X {
public Y Y { get; set; }
}
类型在里面?
例如,我有以下类型:
Y
我们说这个函数返回Expression
private static Expression<Func<Y, bool>> ExprY(Y y2)
{
return y1 => y1.Something == y2.Something;
}
:
Y
如您所见,我可以向此函数发送Expression<Func<Y, bool>>
个对象,它将返回Expression
。
现在,让我们说我想创建相同的X
但是来自private static Expression<Func<X, bool>> ExprX(X x2)
{
return x1 => x1.Y.Something == x2.Y.Something;
}
,这样我就可以这样写:
Something
这很好用,但我复制代码,因为比较ExprX
的内容与两个函数内部相同,所以问题是如何重写ExprY
以某种方式在其内部使用Something
所以我不需要重复public static Expression<Func<X, bool>> ExprX(X x2)
{
return x1 => ExprY(x2.Y)(x1.Y);
}
比较?
类似的东西:
.Where
PS。这是由实体框架6在RUN apt-get install -y locales
RUN locale-gen en_US.UTF-8
RUN update-locale en_US.UTF-8
子句中运行的代码,因此答案需要与该框架一起使用。
答案 0 :(得分:2)
您可以使用ExpressionVisitor
将表达式中的所有Y
替换为x.Y
并构建新表达式。
class ReplaceParameterExpressionVisitor : ExpressionVisitor
{
private readonly Expression _target, _replacement;
public ReplaceParameterExpressionVisitor(ParameterExpression target, Expression replacement)
{
_target = target;
_replacement = replacement;
}
protected override Expression VisitParameter(ParameterExpression node)
{
return node.Equals(_target) ? _replacement : node;
}
}
访问者非常简单,找到目标ParameterExpression
并将其替换为_replacement
表达式。
public static class ExpressionExtensions
{
public static Expression<Func<T, R>> ReplaceParameter<T, R, U>(this Expression<Func<U, R>> origin, Expression<Func<T, U>> accessor)
{
var originalParameter = origin.Parameters.Single();
var replacement = accessor.Body;
var visitor = new ReplaceParameterExpressionVisitor(originalParameter, replacement);
var newBody = visitor.Visit(origin.Body);
return Expression.Lambda<Func<T, R>>(newBody, accessor.Parameters.Single());
}
}
上面的扩展方法将使用visitor替换body中的参数,获取新的body,并使用new参数构建一个新的lambda表达式。
class User
{
public string Name { get; set; }
}
Expression<Func<string, bool>> exp = s => s.Equals("Jack");
Expression<Func<User, string>> nameAccessor = u => u.Name;
var newExp = exp.ReplaceParameter(nameAccessor); // u => u.Name.Equals("Jack")