如何使用表达式树为PLINQ构建动态查询

问题描述:

我想为PLINQ定制定制的OrderBy,但我不知道该怎么做.

I want to bild customized OrderBy for PLINQ, but I don't know how to.

对于IQueryable,使用可以使用以下代码:

For IQueryable, use can use below code:

public static class QueryableExtensions
{
    public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        var type = typeof(T);
        var property = type.GetProperty(sortProperty);
        var parameter = Expression.Parameter(type, "p");
        var propertyAccess = Expression.MakeMemberAccess(parameter, property);
        var orderByExp = Expression.Lambda(propertyAccess, parameter);
        var typeArguments = new Type[] { type, property.PropertyType };
        var methodName = sortOrder == ListSortDirection.Ascending ? "OrderBy" : "OrderByDescending";
        var resultExp = Expression.Call(typeof(Queryable), methodName, typeArguments, source.Expression, Expression.Quote(orderByExp));

        return source.Provider.CreateQuery<T>(resultExp);
    }
}

但是对于ParallelQuery,没有这样的属性Provider和Expresss.有人知道怎么做吗?

But for ParallelQuery, there's no such property Provider and Expresss. Does anybody know how to do?

public static class QueryableExtensions
{
    public static ParallelQuery<T> OrderBy<T>(this ParallelQuery<T> source, string sortProperty, ListSortDirection sortOrder)
    {
        ...
    }
}

使用 IQueryable ,您不需要 Provider ,就足以创建表达式并然后直接调用 OrderBy / OrderByDescending .唯一的问题是 OrderBy()在sorting属性的类型中是通用的,您不知道(不是静态的).

With IQueryable, you don't need Provider for this, it's enough to create the expression and then directly call OrderBy/OrderByDescending. The only problem is that OrderBy() is generic in the type of the sorting property, which you don't know (not statically).

您可以通过使用反射调用 OrderBy()来解决此问题.或者您可以使用 dynamic :

You can work around that by invoking OrderBy() using reflection. Or you can use dynamic:

public static IQueryable<T> OrderBy<T>(this IQueryable<T> source, string sortProperty, ListSortDirection sortOrder)
{
    var type = typeof(T);
    var property = type.GetProperty(sortProperty);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByExp = Expression.Lambda(propertyAccess, parameter);

    if (sortOrder == ListSortDirection.Ascending)
    {
        return Queryable.OrderBy(source, (dynamic)orderByExp);
    }
    else
    {
        return Queryable.OrderByDescending(source, (dynamic)orderByExp);
    }
}

您可以对PLINQ完全使用它:

And you can use exactly the same with PLINQ:

public static ParallelQuery<T> OrderBy<T>(this ParallelQuery<T> source, string sortProperty, ListSortDirection sortOrder)
{
    var type = typeof(T);
    var property = type.GetProperty(sortProperty);
    var parameter = Expression.Parameter(type, "p");
    var propertyAccess = Expression.MakeMemberAccess(parameter, property);
    var orderByFunc = Expression.Lambda(propertyAccess, parameter).Compile();

    if (sortOrder == ListSortDirection.Ascending)
    {
        return ParallelEnumerable.OrderBy(source, (dynamic)orderByFunc);
    }
    else
    {
        return ParallelEnumerable.OrderByDescending(source, (dynamic)orderByFunc);
    }
}