转换表达式<func <t1,bool>&gt;表达式<func <t2,bool>动态</func <t2,bool> </func <t1,bool>

时间:2013-03-04 22:58:09

标签: c# linq reflection lambda

我找不到从Expression&lt; Func&lt; T1,bool&gt;&gt;转换的方式到表达式&lt; Func&lt; T2,bool&gt;&gt;。因为我使用了大量的反射,事实上,我真正需要的是一个采用类型参数并执行转换的方法。

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

T2来自T1

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

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

我在基类

上定义了一个过滤表达式
Expression<Func<T1,bool>> filter = p => p.FamilyId == [some value]

我想申请列表&lt; T2&gt;

3 个答案:

答案 0 :(得分:10)

这是你要找的吗?该方法有两种形式:第一种允许您将新输入类型作为参数传递;第二个允许您将输入类型作为泛型参数传递,并获得强类型的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);
        }
    }

答案 1 :(得分:0)

你要求的是非常不明智的。编译器如何知道T1是否可以转换为T2?似乎即使有可能也要求可怕的运行时错误。*

(*我认为不可能,因为你试图将反射与嵌套泛型类型结合起来。)

答案 2 :(得分:0)

您希望将两个表达式T2合并为T1转换,而不是使用给定结果调用expr

这个问题一般会讨论Combining two expressions (Expression<Func<T, bool>>)。对于您的情况,我认为您需要Expression.Call来构建转换表达式,而不是再次使用转换结果调用原始表达式。