所有都在标题中说,更确切地说,我正在寻找转换
的方法 Expression<Func<TDerived, out bool>>
至Expression<Func<TBase, out bool>>
,
TDerived来自TBase。
我怎样才能做到这一点?
答案 0 :(得分:1)
给出像这样的Expression
替换者:
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
// A simple expression visitor to replace some nodes of an expression
// with some other nodes. Can be used with anything, not only with
// ParameterExpression
public class SimpleExpressionReplacer : ExpressionVisitor
{
public readonly Dictionary<Expression, Expression> Replaces;
public SimpleExpressionReplacer(Expression from, Expression to)
{
Replaces = new Dictionary<Expression, Expression> { { from, to } };
}
public SimpleExpressionReplacer(Dictionary<Expression, Expression> replaces)
{
// Note that we should really clone from and to... But we will
// ignore this!
Replaces = replaces;
}
public SimpleExpressionReplacer(IEnumerable<Expression> from, IEnumerable<Expression> to)
{
Replaces = new Dictionary<Expression, Expression>();
using (var enu1 = from.GetEnumerator())
using (var enu2 = to.GetEnumerator())
{
while (true)
{
bool res1 = enu1.MoveNext();
bool res2 = enu2.MoveNext();
if (!res1 || !res2)
{
if (!res1 && !res2)
{
break;
}
if (!res1)
{
throw new ArgumentException("from shorter");
}
throw new ArgumentException("to shorter");
}
Replaces.Add(enu1.Current, enu2.Current);
}
}
}
public override Expression Visit(Expression node)
{
Expression to;
if (node != null && Replaces.TryGetValue(node, out to))
{
return base.Visit(to);
}
return base.Visit(node);
}
}
现在我们可以,
public class Base
{
public int ValueBase { get; set; }
}
public class Derived : Base
{
public int ValueDerived { get; set; }
}
和
Expression<Func<Derived, bool>> exp = x => x.ValueBase == 0;
然后
ParameterExpression parOld = exp.Parameters[0];
ParameterExpression parNew = Expression.Parameter(typeof(Base));
// Replace the parOld with the parNew
Expression body2 = new SimpleExpressionReplacer(parOld, parNew).Visit(exp.Body);
// Note that we have to rebuild the Expression.Lambda<>
Expression<Func<Base, bool>> expNew = Expression.Lambda<Func<Base, bool>>(body2, parNew);
这会产生一个
Expression<Func<Base, bool>> exp = x => x.ValueBase == 0;
请注意,如果您想改为:
Expression<Func<Derived, bool>> exp = x => x.ValueDerived == 0;
到
Expression<Func<Base, bool>> exp = x => ((Derived)x).ValueDerived == 0;
然后你需要这样的东西:
ParameterExpression parOld = exp.Parameters[0];
ParameterExpression parNew = Expression.Parameter(typeof(Base));
UnaryExpression convert = Expression.Convert(parNew, typeof(Derived));
Expression body2 = new SimpleExpressionReplacer(parOld, convert).Visit(exp.Body);
Expression<Func<Base, bool>> expNew = Expression.Lambda<Func<Base, bool>>(body2, parNew);
答案 1 :(得分:0)
你需要包装内部表达式。像
这样的东西var argument = Expression.Parameter(typeof(TDerived));
Expression.Lambda<Func<TDerived, bool>>
(
Expression.Invoke(innerExpression, argument),
argument
);
当然,根据方向,您可能需要对innerExpression
的参数进行显式强制转换 - 这很简单,只需使用Expression.Cast
。
修改强>
为了适应您的编辑,倒置的变体:
var argument = Expression.Parameter(typeof(TBase));
Expression.Lambda<Func<TBase, bool>>
(
Expression.Invoke(innerExpression, Expression.Convert(argument, typeof(TDerived))),
argument
);
请注意,这显然仅在参数的运行时类型派生自TDerived
时才有效。