2011-05-30 179 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(); 
} 
相關問題