替换表达式树中的类型 [英] Replace a type in an expression tree

查看:115
本文介绍了替换表达式树中的类型的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在努力修改表达式树。我已经简化了这个例子,使其更容易在这里显示。我们从两个类开始:

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

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

Filter类中的所有属性也存在于Entity类中。现在我想使用Filter类返回所需的实体,方法如下:

  public IEnumerable< Entity> GetEntities(Expression< Func< Filter,bool>> filter)
{
表达式&FunC< Entity,bool>> conversionFilter = Expression.Lambda filter.Body,
Expression.Parameter(typeof(Entity),filter.Parameters [0] .Name));

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

所以基本上我只是改变表达式参数的类型。现在我调用这样的函数:

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

我收到一个例外,指出在指定的查询中找不到参数x表达。显然通过替换ParameterExpression我正在打破某些东西。如何创建一个正确类型的新表达式,它接管(或重建)原始表达式的正文?

解决方案

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



由于我不太需要Filter类,所以我创建了一个只有属性的界面我想要能够过滤(IEntity)并修改Entity类来实现它。现在我可以得到所需的结果:

  //使用示例:return entities.Entities.Where(ExpressionTransformer< ; IEntity,实体> .Transform(过滤器)); 
内部静态类ExpressionTransformer< TFrom,TTo>其中TTo:TFrom
{
public class Visitor:ExpressionVisitor
{
private ParameterExpression _parameter;

public Visitor(ParameterExpression参数)
{
_parameter =参数;
}

protected override表达式访问参数(ParameterExpression node)
{
return _parameter;
}
}

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

如果你需要做类似的事情,但你不能使用界面,或者您无法使您的课程实现该界面:答案也在上述答案


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 ?

解决方案

After some more searching I found the answer here: How to change a type in an expression tree?. It didn't show up in the suggestions when I submitted my question.

As I don't really need the Filter class, I instead created an interface with only the properties that I want to be able to filter (IEntity) and modified the Entity class to implement it. Now I'm able to get the desired results with this:

// 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);
    }
}

In case you need to do something similar but you cannot work with an interface or you cannot make your class implement that interface: the answer is also in the above mentioned answer

这篇关于替换表达式树中的类型的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆