2009-11-19 110 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

相关问题