3

I'm struggling with the modification of an expression tree. I've simplified the example to make it easier to display here. Let's start with two classes:

    public class Filter
    {
        public string FilterableProperty1 { get; set; }
        public string FilterableProperty2 { get; set; }
    }

    public class Entity
    {
        public string FilterableProperty1 { get; set; }
        public string FilterableProperty2 { get; set; }
        public string NonFilterableProperty { get; set; }
    }

All properties in the Filter class also exist in the Entity class. Now I would like to use the Filter class to return the desired entities with a method like this:

    public IEnumerable<Entity> GetEntities(Expression<Func<Filter, bool>> filter)
    {
        Expression<Func<Entity, bool>> convertedFilter = Expression.Lambda<Func<Entity, bool>>(
            filter.Body,
            Expression.Parameter(typeof(Entity), filter.Parameters[0].Name));

        using (MyEntities entities = new MyEntities())
        {
            return entities.Entities.Where(convertedFilter);
        }
    }

So basically I just change the type of the expression parameter. Now when I call the function like this:

    public IEnumerable<Entity> GetFilteredEntities()
    {
        return GetEntities(x => x.FilterableProperty1 == "Test");
    }

I get an exception saying that the parameter x was not found in the specified query expression. Obviously by replacing the ParameterExpression I am breaking something. How can I create a new expression with the correct type that takes over (or rebuilds) the body of the original expression ?

4

1 回答 1

4

经过更多搜索后,我在这里找到了答案:如何更改表达式树中的类型?. 当我提交我的问题时,它没有出现在建议中。

由于我并不真正需要 Filter 类,因此我创建了一个接口,其中仅包含我希望能够过滤的属性 (IEntity),并修改了 Entity 类来实现它。现在,我可以通过以下方式获得所需的结果:

// Example use: return entities.Entities.Where(ExpressionTransformer<IEntity,Entity>.Transform(filter));
internal static class ExpressionTransformer<TFrom, TTo> where TTo : TFrom
{
    public class Visitor : ExpressionVisitor
    {
        private ParameterExpression _parameter;

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

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

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

如果您需要做类似的事情但您不能使用接口或者您不能让您的类实现该接口:答案也在上述答案中

于 2013-06-10T20:02:55.503 回答