2015-05-29 43 views
4

我有兩個類:如何更正替換類型的表達式?

public class DalMembershipUser 
{ 
     public string UserName { get; set; } 
     //other members 
} 

public class MembershipUser 
{ 
     public string UserName { get; set; } 
     //other members 
} 

我有功能:

public IEnumerable<DalMembershipUser> GetMany(Expression<Func<DalMembershipUser, bool>> predicate) 
    { 
     //but here i can use only Func<MembershipUser, bool> 
     //so i made transformation 
     query = query.Where(ExpressionTransformer<DalMembershipUser,MembershipUser>.Tranform(predicate)); 
} 

當前實現:

public static class ExpressionTransformer<TFrom, TTo> 
    { 
     public class Visitor : ExpressionVisitor 
     { 
      private ParameterExpression _targetParameterExpression; 

      public Visitor(ParameterExpression parameter) 
      { 
       _targetParameterExpression = parameter; 
      } 

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

     public static Expression<Func<TTo, bool>> Tranform(Expression<Func<TFrom, bool>> expression) 
     { 
      ParameterExpression parameter = Expression.Parameter(typeof(TTo), expression.Parameters[0].Name); 
      Expression body = expression.Body; 
      new Visitor(parameter).Visit(expression.Body); 
      return Expression.Lambda<Func<TTo, bool>>(body, parameter); 
     } 
    } 

//某處:.GetMany(u => u.UserName == "username");

例外:房產「系統。字符串用戶名'未定義爲類型'Memb ershipUser'
at line:new Visitor(parameter).Visit(expression.Body);

+0

第二個塊中的查詢定義在哪裏? –

+0

我編輯了你的標題。請參閱:「[應該在其標題中包含」標籤「](http://meta.stackexchange.com/questions/19190/)」,其中的共識是「不,他們不應該」。 –

+0

只是好奇。這一切的目的是什麼? – Kryptos

回答

0

最後它的工作。但仍然不明白爲什麼清除參數創建: Expression.Parameter(typeof(TTo), from.Parameters[i].Name);不工作,需要提取。

public static class ExpressionHelper 
    { 

     public static Expression<Func<TTo, bool>> TypeConvert<TFrom, TTo>(
      this Expression<Func<TFrom, bool>> from) 
     { 
      if (from == null) return null; 

      return ConvertImpl<Func<TFrom, bool>, Func<TTo, bool>>(from); 
     } 

     private static Expression<TTo> ConvertImpl<TFrom, TTo>(Expression<TFrom> from) 
      where TFrom : class 
      where TTo : class 
     { 
      // figure out which types are different in the function-signature 

      var fromTypes = from.Type.GetGenericArguments(); 
      var toTypes = typeof(TTo).GetGenericArguments(); 

      if (fromTypes.Length != toTypes.Length) 
       throw new NotSupportedException("Incompatible lambda function-type signatures"); 

      Dictionary<Type, Type> typeMap = new Dictionary<Type, Type>(); 
      for (int i = 0; i < fromTypes.Length; i++) 
      { 
       if (fromTypes[i] != toTypes[i]) 
        typeMap[fromTypes[i]] = toTypes[i]; 
      } 

      // re-map all parameters that involve different types 
      Dictionary<Expression, Expression> parameterMap = new Dictionary<Expression, Expression>(); 
      ParameterExpression[] newParams = GenerateParameterMap<TFrom>(from, typeMap, parameterMap); 

      // rebuild the lambda 
      var body = new TypeConversionVisitor<TTo>(parameterMap).Visit(from.Body); 
      return Expression.Lambda<TTo>(body, newParams); 
     } 

     private static ParameterExpression[] GenerateParameterMap<TFrom>(
      Expression<TFrom> from, 
      Dictionary<Type, Type> typeMap, 
      Dictionary<Expression, Expression> parameterMap 
     ) 
      where TFrom : class 
     { 
      var newParams = new ParameterExpression[from.Parameters.Count]; 

      for (int i = 0; i < newParams.Length; i++) 
      { 
       Type newType; 
       if (typeMap.TryGetValue(from.Parameters[i].Type, out newType)) 
       { 
        parameterMap[from.Parameters[i]] = newParams[i] = Expression.Parameter(newType, from.Parameters[i].Name); 
       } 
      } 
      return newParams; 
     } 


     class TypeConversionVisitor<T> : ExpressionVisitor 
     { 
      private readonly Dictionary<Expression, Expression> parameterMap; 

      public TypeConversionVisitor(Dictionary<Expression, Expression> parameterMap) 
      { 
       this.parameterMap = parameterMap; 
      } 

      protected override Expression VisitParameter(ParameterExpression node) 
      { 
       // re-map the parameter 
       Expression found; 
       if (!parameterMap.TryGetValue(node, out found)) 
        found = base.VisitParameter(node); 
       return found; 
      } 
      public override Expression Visit(Expression node) 
      { 
       LambdaExpression lambda = node as LambdaExpression; 
       if (lambda != null && !parameterMap.ContainsKey(lambda.Parameters.First())) 
       { 
        return new TypeConversionVisitor<T>(parameterMap).Visit(lambda.Body); 
       } 
       return base.Visit(node); 
      } 

      protected override Expression VisitMember(MemberExpression node) 
      { 
       // re-perform any member-binding 
       var expr = Visit(node.Expression); 
       if (expr.Type != node.Type) 
       { 
        if (expr.Type.GetMember(node.Member.Name).Any()) 
        { 
         MemberInfo newMember = expr.Type.GetMember(node.Member.Name).Single(); 
         return Expression.MakeMemberAccess(expr, newMember); 
        } 
       } 
       return base.VisitMember(node); 
      } 
     } 
    } 
0

您需要使用Visit方法返回的結果表達式。

只是改變:

Expression body = expression.Body; 
new Visitor(parameter).Visit(expression.Body); 

通過

Expression body = new Visitor(parameter).Visit(expression.Body); 
+0

沒有什麼改變; –