2014-10-08 153 views
4

有沒有辦法將屬性選擇器Expression<Func<T, TProperty>>轉換爲Expression<Func<object, object>>,反之亦然?我已經知道如何轉換爲使用Expression<Func<T, object>> ...將表達式<Func <T,TProperty >>轉換爲表達式<Func <object,object >>,反之亦然

Expression<Func<T, TProperty>> oldExp; 
Expression.Lambda<Func<T, object>>(Expression.Convert(oldExp.Body, typeof(object)), oldExp.Parameters); 

...但我需要有效地投兩中,參數和函數的結果,而不僅僅是例如用ExpressionVisitor替換他們,因爲他們需要稍後會被推出。

回答

6

你說得對,你需要使用ExpressionVisitor和ExpressionConvert。

這裏有你要的這兩種方法(以及一些支持方法):

public Expression<Func<object, object>> ConvertToObject<TParm, TReturn>(Expression<Func<TParm, TReturn>> input) 
{ 
    var parm = Expression.Parameter(typeof(object)); 
    var castParm = Expression.Convert(parm, typeof(TParm)); 
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm); 
    body = Expression.Convert(body, typeof(object)); 
    return Expression.Lambda<Func<object, object>>(body, parm); 
} 

public Expression<Func<TParm, TReturn>> ConvertBack<TParm, TReturn>(Expression<Func<object, object>> input) 
{ 
    var parm = Expression.Parameter(typeof(TParm)); 
    var castParm = Expression.Convert(parm, typeof(object)); 
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm); 
    body = Expression.Convert(body, typeof(TReturn)); 
    return Expression.Lambda<Func<TParm, TReturn>>(body, parm); 
} 

Expression ReplaceExpression(Expression body, Expression source, Expression dest) 
{ 
    var replacer = new ExpressionReplacer(source, dest); 
    return replacer.Visit(body); 
} 

public class ExpressionReplacer : ExpressionVisitor 
{ 
    Expression _source; 
    Expression _dest; 

    public ExpressionReplacer(Expression source, Expression dest) 
    { 
     _source = source; 
     _dest = dest; 
    } 

    public override Expression Visit(Expression node) 
    { 
     if (node == _source) 
      return _dest; 

     return base.Visit(node); 
    } 
} 

使用範例:

Expression<Func<Customer, string>> expression = c => c.Name; 
var convertedExpression = ConvertToObject<Customer, string>(expression); 
var backExpression = ConvertBack<Customer, string>(convertedExpression); 

我們當然可以替換原來的兩個方法有一個使用更多類型參數的方法:

public Expression<Func<TTargetParm, TTargetReturn>> ConvertGeneric<TParm, TReturn, TTargetParm, TTargetReturn>(Expression<Func<TParm, TReturn>> input) 
{ 
    var parm = Expression.Parameter(typeof(TTargetParm)); 
    var castParm = Expression.Convert(parm, typeof(TParm)); 
    var body = ReplaceExpression(input.Body, input.Parameters[0], castParm); 
    body = Expression.Convert(body, typeof(TTargetReturn)); 
    return Expression.Lambda<Func<TTargetParm, TTargetReturn>>(body, parm); 
} 

樣本用法:

Expression<Func<Customer, string>> expression = c => c.Name; 
var convertedExpression = ConvertGeneric<Customer, string, object, object>(expression); 
var backExpression = ConvertGeneric<object, object, Customer, string>(convertedExpression); 
相關問題