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

时间:2014-04-08 05:15:00

标签: c# expression-trees plinq

我想为PLINQ bild自定义OrderBy,但我不知道如何。

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

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。 有人知道该怎么做吗?

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

2 个答案:

答案 0 :(得分:0)

只需在并行查询上调用AsQueryable,然后在完成后调用AsParallel以获取并行查询:

public static ParallelQuery<T> OrderBy<T>(this ParallelQuery<T> source, 
    string sortProperty, ListSortDirection sortOrder)
{
    return source.AsQueryable()
        .OrderBy(sortProperty, sortOrder)
        .AsParallel();
}

答案 1 :(得分:0)

使用IQueryable,您不需要Provider,这足以创建表达式,然后直接致电OrderBy / OrderByDescending 。唯一的问题是OrderBy()在排序属性的类型中是通用的,您不知道(非静态)。

您可以使用反射调用OrderBy()来解决这个问题。或者您可以使用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完全相同的内容:

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