2011-05-13 110 views

回答

1

我不得不之前做到這一點...

public static class ExpressionHelper { 
    public static Expression<Func<object,object>> ConvertParameterToObject<T>(this Expression<Func<T,object>> source){ 
      return source.ReplaceParametersWithBase<T,object,object>(); 
    } 

    public static Expression<Func<TBase,TResult>> ReplaceParameterWithBase<T,TResult,TBase>(this Expression<Func<T,TResult>> lambda) 
     where T :TBase 
    { 
     var param = lambda.Parameters.Single(); 
     return (Expression<Func<TBase,TResult>>) 
      ParameterRebinder.ReplaceParameters(new Dictionary<ParameterExpression, ParameterExpression> 
               { 
                { param, Expression.Parameter(typeof (TBase), param.Name) } 
               }, lambda.Body); 
    } 
} 


public class ParameterRebinder : ExpressionVisitor 
{ 

    private readonly Dictionary<ParameterExpression, ParameterExpression> map; 



    public ParameterRebinder(Dictionary<ParameterExpression, ParameterExpression> map) 
    { 

     this.map = map ?? new Dictionary<ParameterExpression, ParameterExpression>(); 

    } 



    public static Expression ReplaceParameters(Dictionary<ParameterExpression, ParameterExpression> map, Expression exp) 
    { 

     return new ParameterRebinder(map).Visit(exp); 

    } 



    protected override Expression VisitParameter(ParameterExpression p) 
    { 

     ParameterExpression replacement; 

     if (map.TryGetValue(p, out replacement)) 
     { 

      p = replacement; 

     } 

     return base.VisitParameter(p); 

    } 

} 
+0

嘗試使用你的函數'返回新的ParameterRebinder(map).Visit(exp);'帶有錯誤信息:'System.String NewDescription'沒有爲'System.Object'類型定義。 – 2011-05-13 10:10:51

+0

這個錯誤是有道理的。一旦你替換參數,你無法知道對象是什麼類型,所以成員將不會被定義。在這種情況下,你可能需要做一個'Compile()',像'Expression >一樣強制轉換並調用toObj = x => strongTyped.Compile()((T )x)' – smartcaveman 2011-05-13 10:24:18

+0

我試圖自己回答這個問題,並以相同的解決方案結束。轉換不會成功使用其參數而不是對象的其他類型的表達式。 – Mic 2011-11-18 14:28:48

1

怎麼是這樣的:

static Expression<Func<object,object>> ConvertFunction<T>(Expression<Func<T,object>> function)  
{ 
    ParameterExpression p=Expression.Parameter(typeof(object)); 

    return Expression.Lambda<Func<object,object>> 
    (
     Expression.Invoke(function,Expression.Convert(p,typeof(T))), p 
    ); 
} 

那麼你可以說這樣的事情:

Expression<Func<string,object>> foo=s=>s.Length; 
Expression<Func<object,object>> bar=ConvertFunction(foo); 

var call=bar.Compile(); 
Console.Write(call("hello")) ; // Prints 5 
+0

這和'return x => function.Compile()((T)x)'有沒有區別? – smartcaveman 2011-05-13 10:27:59

+0

此方法將表達式從'{o => o.NewDescription}'改爲'{Param_0 =>調用(o => o.NewDescription,Convert(Param_0))}'是否有辦法保持相同的表達式? – 2011-05-13 13:50:22

相關問題