c# - 替换表达式树中的类型

标签 c# linq lambda expression

我正在努力修改表达式树。我已经简化了示例,以便更容易在此处显示。让我们从两个类开始:

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

Filter 类中的所有属性也存在于 Entity 类中。现在我想使用 Filter 类通过这样的方法返回所需的实体:

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

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

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

我得到一个异常,指出在指定的查询表达式中找不到参数 x。显然,通过替换 ParameterExpression,我破坏了一些东西。如何创建一个具有正确类型的新表达式来接管(或重建)原始表达式的主体?

最佳答案

经过更多搜索后,我在这里找到了答案:How to change a type in an expression tree? .当我提交问题时,它没有出现在建议中。

由于我并不真正需要 Filter 类,因此我创建了一个接口(interface),其中仅包含我希望能够过滤的属性 (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);
    }
}

如果你需要做类似的事情但是你不能使用一个接口(interface)或者你不能让你的类实现那个接口(interface):答案也在上面提到的答案中

关于c# - 替换表达式树中的类型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17030821/

相关文章:

c# - 将动态创建的 SQL 参数作为匿名类型传递到 dapper

c# - Lambda 表达式的工作原理

c# - 使用具有鉴别器和多态性的 C# MongoDB v2 驱动程序

C++ lambda 捕获 this vs 通过引用捕获

java - Lambda表达式匿名对象生命周期

scala - lambdas 在 Scala 中是如何工作的,它们是在匿名类之上运行的吗?

c# - C#'s readonly vs C++' s const - 等价物

c# - 我什么时候应该写静态方法?

C#/VB .Net 性能调优,生成所有可能的彩票组合

c# - 将 lambda 表达式转换为派生类型