2011-08-13 165 views
2

我怎樣才能讓一個通用的輔助方法,通過函數求所使用的類型從一種類型轉換爲另一種表達轉換表達<Func鍵<FromType>>以表達<Func<ToType>>

內我有一個Expression<Func<IEmployee, bool>>,我想轉換它到

Expression<Func<Employee, bool>>. 

第二個類型總是實現第一個類型。一個通用的解決方案是我想要實現的。

編輯

我編輯了這個問題更清楚。

回答

4

嗯,你可以創建一個蒙上表達式,然後其參數轉發給原始表達式:

Expression<Func<IEmployee, bool>> source = ... 

var param = Expression.Parameter(typeof(Employee)); 

// Types the argument as the type expected by the source expression 
// and then forwards it... 
var invocationExpr = Expression.Invoke 
        (source, Expression.TypeAs(param, typeof(IEmployee))); 

var result = Expression.Lambda<Func<Employee, bool>>(invocationExpr, param); 

如果供應商不支持調用表達式,你可能會需要一個更加 複雜的解決方案替換源表達式中的參數。

編輯:好吧,既然你說你的提供者不喜歡結果表達式,這裏是一個替代的例子。這是一個真的粗略的參數替代物應該看起來像(我現在只是寫了一個樣本),但它應該適用於您的目的。

public static class ParameterReplacer 
{ 
    // Produces an expression identical to 'expression' 
    // except with 'source' parameter replaced with 'target' parameter.  
    public static Expression<TOutput> Replace<TInput, TOutput> 
       (Expression<TInput> expression, 
        ParameterExpression source, 
        ParameterExpression target) 
    { 
     return new ParameterReplacerVisitor<TOutput>(source, target) 
        .VisitAndConvert(expression); 
    } 

    private class ParameterReplacerVisitor<TOutput> : ExpressionVisitor 
    { 
     private ParameterExpression _source; 
     private ParameterExpression _target; 

     public ParameterReplacerVisitor 
       (ParameterExpression source, ParameterExpression target) 
     { 
      _source = source; 
      _target = target; 
     } 

     internal Expression<TOutput> VisitAndConvert<T>(Expression<T> root) 
     { 
      return (Expression<TOutput>)VisitLambda(root); 
     } 

     protected override Expression VisitLambda<T>(Expression<T> node) 
     { 
      // Leave all parameters alone except the one we want to replace. 
      var parameters = node.Parameters.Select 
          (p => p == _source ? _target : p); 

      return Expression.Lambda<TOutput>(Visit(node.Body), parameters); 
     } 

     protected override Expression VisitParameter(ParameterExpression node) 
     { 
      // Replace the source with the target, visit other params as usual. 
      return node == _source ? _target : base.VisitParameter(node); 
     } 
    } 
} 

,然後用它作爲:

Expression<Func<IEmployee, bool>> expression = ... 

var result = ParameterReplacer.Replace 
       <Func<IEmployee, bool>, Func<Employee, bool>> 
       (expression, 
       expression.Parameters.Single(), 
       Expression.Parameter(typeof(Employee)); 
+0

我正在使用Teleriks OpenAccess,它似乎並不喜歡產生的表達式。 – David

+0

好的,繼續。會給你一個參數替代品的樣本。 – Ani

+0

David做了那個工作嗎? – Ani

3

如果第二類型總是從繼承或實現第一種類型,你可以使用

Func<TOut, bool> Convert<TIn, TOut>(Func<TIn, bool> f) where TOut : TIn 
{ 
    return (TOut x) => f((TIn)x); 
} 

如果沒有這種關係,你不能使用這個仿製藥。

+0

對不起,我應該提到的是肯定的,第二類始終貫徹的第一種類型。 – David

+0

如果我在表達式中使用Func,該怎麼辦? – David

+0

如果你有'Expression >',那麼你*沒有*'Func ',你應該在問題中這麼說,因爲這是一個完全不同的問題。 – svick

相關問題