【发布时间】:2011-05-30 13:53:44
【问题描述】:
有什么简单的转换方法
Expression<Func<TBase,bool>>
到
Expression<Func<T,bool>>
T 是从 TBase 继承的?
【问题讨论】:
标签: c# generics expression-trees
有什么简单的转换方法
Expression<Func<TBase,bool>>
到
Expression<Func<T,bool>>
T 是从 TBase 继承的?
【问题讨论】:
标签: c# generics expression-trees
只要 T 派生自 TBase,您就可以使用原始表达式的主体和参数直接创建所需类型的表达式。
Expression<Func<object, bool>> x = o => o != null;
Expression<Func<string, bool>> y = Expression.Lambda<Func<string, bool>>(x.Body, x.Parameters);
【讨论】:
您可能需要手动转换。这样做的原因是您正在有效地转换为它可能的子集。所有T 都是TBase,但并非所有TBase 都是T。
好消息是您可能可以使用Expression.Invoke 来完成此操作,并手动将适当的转换/转换应用到TBase(当然会发现任何类型安全问题)。
编辑:对于误解您想要进入的方向,我深表歉意。我认为简单地转换表达式仍然是您最好的方法。它使您能够随心所欲地处理转换。 Marc Gravell's answer here 是我见过的最简洁明了的方式。
【讨论】:
为了做到这一点,我编写了 ExpressionVisitor 并重载了 VisitLambda 和 VisitParameter
这里是:
public class ConverterExpressionVisitor<TDest> : ExpressionVisitor
{
protected override Expression VisitLambda<T>(Expression<T> node)
{
var readOnlyCollection = node.Parameters.Select(a => Expression.Parameter(typeof(TDest), a.Name));
return Expression.Lambda(node.Body, node.Name, readOnlyCollection);
}
protected override Expression VisitParameter(ParameterExpression node)
{
return Expression.Parameter(typeof(TDest), node.Name);
}
}
public class A { public string S { get; set; } }
public class B : A { }
static void Main(string[] args)
{
Expression<Func<A, bool>> ExpForA = a => a.S.StartsWith("Foo");
Console.WriteLine(ExpForA); // a => a.S.StartsWith("Foo");
var converter = new ConverterExpressionVisitor<B>();
Expression<Func<B, bool>> ExpForB = (Expression<Func<B, bool>>)converter.Visit(ExpForA);
Console.WriteLine(ExpForB); // a => a.S.StartsWith("Foo"); - same as for A but for B
Console.ReadLine();
}
【讨论】: