1

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

2 Answers 2

0

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);
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

One more question, how to avoid boxing/unboxing if I have the sortProperty returns type object, but always stored the value hasing integer type?
@luciferlu If the type of the property is object, then the value will be already boxed, no matter what. And I think this code won't unbox it.
in the case I mentioned, somehow, we can add below code to improve the perfomrance: propertyAccess = Expression.Convert(propertyAccess, [target type])
0

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

2 Comments

But will this actually execute that OrderBy() in parallel?
Thanks, but actually this can't work. It will throw StackOverflow.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.