2013-02-18 2 views
9

는 나는이 같은 방법이있다.표현식 트리에서 유형을 변경하는 방법은 무엇입니까? 나는 또 다른 유형으로 <code>IPerson</code> 유형을 변경하려면이 방법</p> <pre><code>private bool Method_1(Expression<Func<IPerson, bool>> expression) { /* Some code that will call Method_2 */ } </code></pre> <p>:

private bool Method_2(Expression<Func<PersonData, bool>> expression) 
{ 
    /* Some code */ 
} 

그래서, method_1에 내가 PersonDataIPerson을 변경해야합니다 :이처럼 보이는 다른 방법을 호출 할. 어떻게해야합니까?

편집 :

내가 전화

: Method_1(p => p.Id == 1) 내가 조건 ( p.Id == 1)을 '저장'을 싶지만 또 다른 유형, 즉 IPerson에이 조건을 실행합니다. 그래서, 내가 표현을 변경하거나 IPerson

편집 II와 새로운 표현 작성해야합니다 :이

private class CustomExpressionVisitor<T> : ExpressionVisitor 
{ 
    ParameterExpression _parameter; 

    public CustomExpressionVisitor(ParameterExpression parameter) 
    { 
     _parameter = parameter; 
    } 

    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     return _parameter; 
    } 

    protected override Expression VisitMember(MemberExpression node) 
    { 
     if (node.Member.MemberType == System.Reflection.MemberTypes.Property) 
     { 
      MemberExpression memberExpression = null; 
      var memberName = node.Member.Name; 
      var otherMember = typeof(T).GetProperty(memberName); 
      memberExpression = Expression.Property(Visit(node.Expression), otherMember); 
      return memberExpression; 
     } 
     else 
     { 
      return base.VisitMember(node); 
     } 
    } 
} 

그리고 : 관심있는 사람들을 위해

을, 이것은 내 솔루션 (지금은)입니다 이다 내가 그것을 사용하는 방법 : 당신은 .NET 4 사용하는 경우

public virtual bool Exists(Expression<Func<Dto, bool>> expression) 
{ 
    var param = Expression.Parameter(typeof(I)); 
    var result = new CustomExpressionVisitor<I>(param).Visit(expression.Body); 
    Expression<Func<I, bool>> lambda = Expression.Lambda<Func<I, bool>>(result, param); 

    bool exists = _repository.Exists(lambda); 
    return exists; 
} 
+1

'IPerson'과 'PersonData'사이에는 어떤 관계가 있습니까? – GolfWolf

+0

@ w0lf 아니요, 그들은 서로를 알지 못합니다. 'PersonData'는 인터페이스의 DTO 버전 ('IPerson')입니다. – Martijn

+0

어떻게 할 수 있는지 모르겠습니다. 구체적인 표현식이 어떻게 생겼는지 예를 게시하고 수동으로 할 수 있다면'PersonData'를 사용하도록 어떻게 변환 할 수 있습니까? – GolfWolf

답변

15

이 용이하다 (갱신 : 코멘트 ExpressionVisitor에서 언급 한 바와 같이하지 4.5 버전 4에서 추가되었다)가 ​​필요 이전 프레임 워크에 대한 인터넷 검색 :

일부 가정이 있지만 DTO 및 엔티티 시나리오에서 유효하다고 생각합니다. 액세스 된 속성은 일치해야합니다. 개념의

class Visitor<T> : ExpressionVisitor 
{ 
    ParameterExpression _parameter; 

    //there must be only one instance of parameter expression for each parameter 
    //there is one so one passed here 
    public Visitor(ParameterExpression parameter) 
    { 
     _parameter = parameter; 
    } 

    //this method replaces original parameter with given in constructor 
    protected override Expression VisitParameter(ParameterExpression node) 
    { 
     return _parameter; 
    } 

    //this one is required because PersonData does not implement IPerson and it finds 
    //property in PersonData with the same name as the one referenced in expression 
    //and declared on IPerson 
    protected override Expression VisitMember(MemberExpression node) 
    { 
     //only properties are allowed if you use fields then you need to extend 
     // this method to handle them 
     if (node.Member.MemberType != System.Reflection.MemberTypes.Property) 
      throw new NotImplementedException(); 

     //name of a member referenced in original expression in your 
     //sample Id in mine Prop 
     var memberName = node.Member.Name; 
     //find property on type T (=PersonData) by name 
     var otherMember = typeof(T).GetProperty(memberName); 
     //visit left side of this expression p.Id this would be p 
     var inner = Visit(node.Expression); 
     return Expression.Property(inner, otherMember); 
    } 
} 

증명 : .NET 4에서

class PersonData 
{ 
    public bool Prop { get; set; } 
} 

interface IPerson 
{ 
    bool Prop { get; set; } 
} 

당신은 당신이 그것의 구현을 작성하거나 찾을 필요가 다음 하나 나이를 사용하는 경우이 훨씬 쉽게 정의 ExpressionVisitor 클래스가

class Program 
{ 
    static void Main() 
    { 
     //sample expression 
     Expression<Func<IPerson, bool>> expression = x => x.Prop; 

     //parameter that will be used in generated expression 
     var param = Expression.Parameter(typeof(PersonData)); 
     //visiting body of original expression that gives us body of the new expression 
     var body = new Visitor<PersonData>(param).Visit(expression.Body); 
     //generating lambda expression form body and parameter 
     //notice that this is what you need to invoke the Method_2 
     Expression<Func<PersonData, bool>> lambda = Expression.Lambda<Func<PersonData, bool>>(body, param); 
     //compilation and execution of generated method just to prove that it works 
     var boolValue = lambda.Compile()(new PersonData()); 
    } 
} 

간단한 표현식에 대해서도 적용됩니다. x.Prop.Prop1 < 3을 처리해야하는 경우이 문제를 더욱 확장해야합니다.

+0

감사합니다. 코드에 몇 가지 의견을 제시 할 수 있는지 물어 보는 것이 너무 어렵습니까? 표현 (나무)이 실제로 내 전문 분야가 아니기 때문에 나는 이해하기 어렵습니다 ... – Martijn

+1

@Martijn는 괜찮습니까? – Rafal

+0

고마워요! 나는 거의 감히 묻지 않지만, 주 앱에 의견을 제공 할 수 있습니까? – Martijn