2011-05-30 229 views

回答

3

只要为T从TBASE派生,你可以直接创建所需的类型与表达您的原始表情的身体和参数。

Expression<Func<object, bool>> x = o => o != null; 
Expression<Func<string, bool>> y = Expression.Lambda<Func<string, bool>>(x.Body, x.Parameters); 
+0

这太简单了,谢谢! – pil0t 2012-08-22 07:14:37

+0

这是非常好的。 – 2015-09-23 08:19:39

2

您可能需要手动进行转换。这是因为你正在有效地将其转换为可能的子集。所有T均为TBase,但并非全部TBase均为T

好消息是,您可以使用Expression.Invoke进行手动操作,并手动将相应的演员表转换为TBase(当然可以捕捉任何类型的安全问题)。

编辑:我对误解你想要进入的方向表示歉意。我认为简单地转换表达方式仍然是你的最佳途径。它使您能够根据需要处理转换。 Marc Gravell's answer here是我见过的最紧凑和最清晰的方式。

+0

为什么手动?我将E 转换为E >,所以在我使用TBase的每个地方,我都可以使用T. – pil0t 2011-05-30 14:37:00

+0

这是我的错。我误解了你想转换的方向。我原来的答案更新了一个更好的答案的链接比我能够想出。 – drharris 2011-05-30 15:21:38

0

为了这一点,我写了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(); 
} 
相关问题