سؤال

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

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

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)
    {
        ...
    }
}
هل كانت مفيدة؟

المحلول

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).

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

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

نصائح أخرى

Just call AsQueryable on your parallel query, and then call AsParallel when done to get back a parallel query:

public static ParallelQuery<T> OrderBy<T>(this ParallelQuery<T> source, 
    string sortProperty, ListSortDirection sortOrder)
{
    return source.AsQueryable()
        .OrderBy(sortProperty, sortOrder)
        .AsParallel();
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top