2009-11-19 138 views
1

另一個LINQ的問題=)轉換表達<Func鍵<TInterface,布爾>>表達式<Func鍵<TImplementation,布爾>>

所以我有一定的接口,我可以針對編碼並且具有該簽名的表達

Expression<Func<TInterface, bool>> 

在某些時候,我會需要使用的表達,但它需要像這樣

Expression<Func<TImplementaion, bool>> 

我已經試過這

Expression<Func<TImplementation, bool>> expression = x => myExpression.Compile().Invoke(x); 

雖然這編譯表達在翻譯中迷路 任何想法? 謝謝

回答

3

AFAIK BCL對使用表達式的支持非常有限。我擔心你將不得不重寫表達式來改變方法參數類型。它不難,也不容易。基本上,您將克隆Expression(它是一棵樹)的每個節點,但將根節點的數據類型設置爲Func<TImplementation, bool>

我會尋找一個完成相同目標但不具備此鑄造要求的不同設計 - 翻閱表達式並不好玩。

更新我已經實現了一個你想要的功能。我把它叫做CastParam

public static Expression<Func<TOut, bool>> CastParam<TIn, TOut>(this Expression<Func<TIn, bool>> inExpr) { 
    if (inExpr.NodeType == ExpressionType.Lambda && 
     inExpr.Parameters.Count > 0) { 

     var inP = inExpr.Parameters[0]; 
     var outP = Expression.Parameter(typeof(TOut), inP.Name); 

     var outBody = inExpr.Body.ConvertAll(
      expr => (expr is ParameterExpression) ? outP : expr);       
     return Expression.Lambda<Func<TOut,bool>>(
      outBody, 
      new ParameterExpression[] { outP }); 
    } 
    else { 
     throw new NotSupportedException(); 
    } 
} 

它所做的就是重寫表達與新型替代舊ParamaterType。這裏是我的小測試:

class TInterface { public int IntVal; } 
class TImplementation : TInterface { public int ImplVal; } 

void Run() 
{ 
    Expression<Func<TInterface, bool>> intExpr = (i => i.IntVal == 42); 
    Expression<Func<TImplementation, bool>> implExpr = intExpr.CastParam<TInterface, TImplementation>(); 

    Console.WriteLine ("{0} --> {1}", intExpr, implExpr); 

    var c = implExpr.Compile(); 

    Console.WriteLine (c.Invoke (new TImplementation { IntVal = 41, ImplVal = 42 })); 
    Console.WriteLine (c.Invoke (new TImplementation { IntVal = 42, ImplVal = 41 })); 
} 

正如預期的那樣,它打印:

public static Expression Rewrite(this Expression exp, Func<Expression, Expression> c) { 
    Expression clone = null; 
    switch (exp.NodeType) { 
     case ExpressionType.Equal: { 
      var x = exp as BinaryExpression; 
      clone = Expression.Equal(Rewrite(x.Left,c), Rewrite(x.Right,c), x.IsLiftedToNull, x.Method); 
      } break; 
     case ExpressionType.MemberAccess: { 
      var x = exp as MemberExpression; 
      clone = Expression.MakeMemberAccess(Rewrite(x.Expression,c), x.Member); 
      } break; 
     case ExpressionType.Constant: { 
      var x = exp as ConstantExpression; 
      clone = Expression.Constant(x.Value); 
      } break; 
     case ExpressionType.Parameter: { 
      var x = exp as ParameterExpression; 
      clone = Expression.Parameter(x.Type, x.Name); 
      } break; 
     default: 
      throw new NotImplementedException(exp.NodeType.ToString()); 
    } 
    return c(clone); 
} 

False 
True

代碼依賴於Expression重寫,我寫(從下往上重寫表達式樹)

重寫器顯然是不完整的,你需要完成它。

+0

感謝您的快速回答,我很害怕那個:(。我會住另一個問題,以防萬一別人有一些替代想法 – roundcrisis 2009-11-19 19:28:01

+0

絕對可以,最終你可以設置一個賞金,也許有人會爲你寫代碼:-) – 2009-11-19 20:02:00

+0

感謝你們,我做了一些稍微不同的事情(我有一個私人類,它實現了接口,我從設置的屬性中重新創建了它,它只是幾行代碼,但我不是非常糟糕對此感到滿意,所以今天過後我不得不重新考慮這個問題(小今天發佈) – roundcrisis 2009-11-20 11:24:14

相關問題