动态构建表达式树

3

我正在跟随这个优秀的示例:将Linq转换为Sql表达式树

在我的情况下,我试图构建一个表达式树,其中要过滤的类型仅在运行时已知,并且表示为字符串。 在上面的示例中,类型 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"来实现同样的效果的方法呢?

1个回答

4
当然,但是你必须理解其影响。类型名称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调用吗? - dodbrian
1
Expression.Equal() 对应于使用 == 运算符。您无法添加该参数。您需要生成一个等效于 stringVar.Equals(otherStringVar, StringComparison.OrdinalIgnoreCase) 或使用静态的 String.Equals(stringVar, otherStringVar, StringComparison.OrdinalIgnoreCase) 的表达式。 - Jeff Mercado

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接