2013-03-04 14 views
6

nie mogę znaleźć drogę do konwersji z Expression < Func < T1, bool > > ekspresji < Func < T2, bool > >. Ponieważ używam dużo refleksji, tak naprawdę potrzebuję metody, która pobiera parametr typu i wykonuje konwersję.Konwersja Expression <Func <T1,bool>> do Expression <Func <T2,bool> dynamicznie

public object Convert(Expression<Func<T1,bool>> expr, Type t); 

T2 pochodzi od T1

public class T1 { 
    int FamilyId {get; set;} 
} 

public class T2 : T1 { 
    ... other properties 
} 

jestem definiowanie wyrażenie filtru od klasy

Expression<Func<T1,bool>> filter = p => p.FamilyId == [some value] 

bazowej, który chcę zastosować do listy <T2>

+0

'tak naprawdę potrzebuję metody, która pobiera parametr typu i wykonuje konwersję." - Co? po co jest 'bool'? potrzebujesz metody konwersji? lub warunkowy? Nie rozumiem –

+1

W jaki sposób powiązane są 'T1' i' T2'? Czy istnieje nawet sposób na konwersję między nimi? – cdhowie

+0

T2 pochodzi z T1. – Hernan

Odpowiedz

9

Czy tego właśnie szukasz? Istnieją dwa smaki tej metody: pierwsza pozwala przekazać nowy typ danych jako argument; drugi pozwala przekazać typ wejściowy jako parametr ogólny i uzyskać silnie wpisaną LambdaExpression.

public static LambdaExpression ChangeInputType<T, TResult>(Expression<Func<T, TResult>> expression, Type newInputType) 
    { 
     if (!typeof(T).IsAssignableFrom(newInputType)) 
      throw new Exception(string.Format("{0} is not assignable from {1}.", typeof(T), newInputType)); 
     var beforeParameter = expression.Parameters.Single(); 
     var afterParameter = Expression.Parameter(newInputType, beforeParameter.Name); 
     var visitor = new SubstitutionExpressionVisitor(beforeParameter, afterParameter); 
     return Expression.Lambda(visitor.Visit(expression.Body), afterParameter); 
    } 

    public static Expression<Func<T2, TResult>> ChangeInputType<T1, T2, TResult>(Expression<Func<T1, TResult>> expression) 
    { 
     if (!typeof(T1).IsAssignableFrom(typeof(T2))) 
      throw new Exception(string.Format("{0} is not assignable from {1}.", typeof(T1), typeof(T2))); 
     var beforeParameter = expression.Parameters.Single(); 
     var afterParameter = Expression.Parameter(typeof(T2), beforeParameter.Name); 
     var visitor = new SubstitutionExpressionVisitor(beforeParameter, afterParameter); 
     return Expression.Lambda<Func<T2, TResult>>(visitor.Visit(expression.Body), afterParameter); 
    } 

    public class SubstitutionExpressionVisitor : ExpressionVisitor 
    { 
     private Expression before, after; 
     public SubstitutionExpressionVisitor(Expression before, Expression after) 
     { 
      this.before = before; 
      this.after = after; 
     } 
     public override Expression Visit(Expression node) 
     { 
      return node == before ? after : base.Visit(node); 
     } 
    } 
+2

doskonałe! dokładnie to, czego szukałem. Dzięki!!!! – Hernan

+0

Czy jest możliwe, aby podobne wyrażenie, gdy T2 nie dziedziczy z T1? –

0

To, o co prosisz, jest bardzo nierozsądne. W jaki sposób kompilator kiedykolwiek wiedziałby, czy T1 można przekonwertować na T2? Wygląda na to, prosząc o okropnych błędów run-time, nawet jeśli jest to możliwe. *

(* nie sądzę, jego możliwe, ponieważ staramy się połączyć refection z zagnieżdżonych typów generycznych.)

+0

T2 pochodzi od T1 – Hernan

0

Wygląda na to, chcesz połączyć 2 wyrażenia - T2 do T1 konwersji, a następnie zadzwonić pod numer expr z podanym wynikiem.

W tym pytaniu omówiono ogólnie: Combining two expressions (Expression<Func<T, bool>>). W twoim przypadku myślę, że potrzebujesz Expression.Call do skonstruowania wyrażenia konwersji, a następnie ponownego wywołania oryginalnego wyrażenia z wynikiem konwersji.

Powiązane problemy