2009-11-19 5 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>으로 설정합니다.

같은 목표를 달성했지만 다른 주조 요구 사항이없는 다른 디자인을 찾아 볼 것입니다. 표현을 통해 갈고 닦는 것은 재미 있지 않습니다.

업데이트 나는 원하는대로 기능을 구현했습니다. 그것은이하는 모든 새로운 유형의 이전 ParamaterType 대체 표현을 재 작성

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(); 
    } 
} 

: 나는 그것을 CastParam를 호출합니다.

예상대로
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); 
} 
:

코드는 내가 쓴 Expression 라이터에 의존
False 
True

은 (아래에서 위로 식 트리를 재 작성)

재 작성자가 분명히 불완전하기 때문에 완료해야합니다.

+0

빠른 답변을 주셔서 감사합니다. 나는 두려웠습니다. (누군가에게 몇 가지 대안 아이디어가있는 경우에 대비해 다른 질문을 던지기로하겠습니다.) – roundcrisis

+0

또한 결국에는 현상금을 설정할 수 있습니다. :-) –

+0

나는이 인터페이스를 구현하는 private 클래스를 가지고 있으며 setted 속성에서 다시 만들었다. 약간의 코드 라인을 가지고 있지만별로 끔찍하지 않다. 그것으로 행복해 오늘 오늘 작은 발표를 다시해야 할 것입니다 – roundcrisis

관련 문제