【问题标题】:Dynamically building an expression tree动态构建表达式树
【发布时间】:2016-07-15 22:54:02
【问题描述】:

我正在关注这个优秀的例子:Convert Linq to Sql Expression to Expression Tree

在我的例子中,我正在尝试构建一个表达式树,其中要过滤的类型仅在运行时才知道,并表示为字符串。在上面的例子中,类型 Region 是已知的并且可以直接输入:

ParameterExpression pe = Expression.Parameter(typeof(Region), "region");

在我的应用程序中,我已经能够将其重写为:

ParameterExpression pe = Expression.Parameter(Type.GetType("mystring"), "listData");

我的绊脚石是这个例子:

MethodCallExpression whereCallExpression = Expression.Call(
            typeof(Queryable),
            "Where",
            new Type[] { query.ElementType },
            query.Expression,
            Expression.Lambda<Func<Region, bool>>(e3, new ParameterExpression[] { pe }));
var results = query.Provider.CreateQuery<Region>(whereCallExpression);

在这两行中,Region 是直接输入的。有没有办法动态地使用字符串“Region”来达到同样的效果?

【问题讨论】:

    标签: c# linq expression-trees


    【解决方案1】:

    当然可以,但您必须了解其中的含义。类型名称Region 是编译时类型。使用它,您可以生成强类型查询。但是,由于您在编译时没有类型,您可以仍然生成查询,但它不会是强类型的。

    您可以使用非泛型重载生成未知编译时类型的 lambda 表达式。 CreateQuery() 方法也是如此。

    这是同一查询的两个版本,用于检查某些属性值是否与给定值匹配。一个是通用的,另一个不是。

    泛型版本隐式地从查询类型中获取类型。

    public IQueryable<TSource> PropertyEqualsValue<TSource>(IQueryable<TSource> query,
            string propertyName, object value)
    {
        var param = Expression.Parameter(typeof(TSource));
        var body = Expression.Equal(
            Expression.Property(param, propertyName),
            Expression.Constant(value)
        );
        var expr = Expression.Call(
            typeof(Queryable),
            "Where",
            new[] { typeof(TSource) },
            query.Expression,
            Expression.Lambda<Func<TSource, bool>>(body, param)
        );
        return query.Provider.CreateQuery<TSource>(expr);
    }
    
    var query = PropertyEqualsValue(SomeTable, "SomeColumn", "SomeValue");
    

    而另一个类型取自提供的typeName。请注意,创建查询时,我们无法提供类型,因为在编译时我们不知道类型是什么。

    public IQueryable PropertyEqualsValue(IQueryable query,
            Type type, string propertyName, object value)
    {
        var param = Expression.Parameter(type);
        var body = Expression.Equal(
            Expression.Property(param, propertyName),
            Expression.Constant(value)
        );
        var expr = Expression.Call(
            typeof(Queryable),
            "Where",
            new[] { type },
            query.Expression,
            Expression.Lambda(body, param)
        );
        return query.Provider.CreateQuery(expr);
    }
    
    var type = Type.GetType("Some.Type.Name");
    var query = PropertyEqualsValue(SomeTable, type, "SomeColumn", "SomeValue");
    

    【讨论】:

    • 知道如何将 StringComparison.OrdinalIgnoreCase 传递给 Expression.Equal 调用吗?
    • Expression.Equal() 对应于== 运算符的使用。您将无法添加该参数。您需要生成一个等效于stringVar.Equals(otherStringVar, StringComparison.OrdinalIgnoreCase) 的表达式或使用静态String.Equals(stringVar, otherStringVar, StringComparison.OrdinalIgnoreCase)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-08
    • 1970-01-01
    • 1970-01-01
    • 2015-12-01
    相关资源
    最近更新 更多