将IComparer参数传递给自定义LINQ OrderBy扩展方法

时间:2013-07-22 20:29:49

标签: c# linq lambda sql-order-by icomparer

经过大量的谷歌搜索和尝试一些事情而没有找到/得到所需的结果后,我决定发布这个问题。

我有自定义的OrderBy扩展方法,现在在执行OrderBy操作时,我想传递AlphanumComparator这样的内容:

return divergences.OrderBy(sort, new AlphanumComparator());

这是扩展方法:

public static IQueryable<T> OrderBy<T>(this IQueryable<T> collection,
    GridSortOptions sortOptions, AlphanumComparator comparer = null)
{
    if (string.IsNullOrEmpty(sortOptions.Column))
    {
        return collection;
    }

    Type collectionType = typeof(T);

    ParameterExpression parameterExpression = Expression.Parameter(collectionType, "p");

    Expression seedExpression = parameterExpression;

    Expression aggregateExpression = sortOptions.Column.Split('.').Aggregate(seedExpression, Expression.Property);

    MemberExpression memberExpression = aggregateExpression as MemberExpression;

    if (memberExpression == null)
    {
        throw new NullReferenceException(string.Format("Unable to cast Member Expression for given path: {0}.", sortOptions.Column));
    }

    LambdaExpression orderByExp = Expression.Lambda(memberExpression, parameterExpression);

    const string orderBy = "OrderBy";

    const string orderByDesc = "OrderByDescending";

    Type childPropertyType = ((PropertyInfo)(memberExpression.Member)).PropertyType;

    string methodToInvoke = sortOptions.Direction == MvcContrib.Sorting.SortDirection.Ascending ? orderBy : orderByDesc;

    MethodCallExpression orderByCall;

    orderByCall = Expression.Call(typeof(Queryable), methodToInvoke, new[] { collectionType, childPropertyType }, collection.Expression, Expression.Quote(orderByExp));

    if(comparer != null)
    {
       // How can I pass the comparator to the OrderBy MethodCallExpression?

       // Using the standard LINQ OrderBy, we can do this:
       // elements.OrderBy(e => e.Index, new AlphanumComparator())
    }

    return collection.Provider.CreateQuery<T>(orderByCall);
}

请参阅代码中的评论,我认为我应该通过IComparer ...我该如何处理?

1 个答案:

答案 0 :(得分:0)

我必须采用不同的方法。

我正在尝试创建与MvcContrib Grid一起使用的通用OrderBy,但将IComparer传递给该自定义OrderBy表达式并不像我想象的那样有效工作

所以我创建了这个帮助器,它接收一个点符号的字符串,如Element1.Standard.Chapter.Manual.Name,然后返回一个Expression<Func<T, string>>

public static Func<T, string> CreateSelectorExpression<T>(string propertyName) where T : class
{
    ParameterExpression parameterExpression = Expression.Parameter(typeof(T));

    Expression aggregateExpression = propertyName.Split('.').
        Aggregate(parameterExpression as Expression, Expression.Property) as MemberExpression;

    LambdaExpression exp = Expression.Lambda(aggregateExpression, parameterExpression);

    return (Func<T, string>)exp.Compile();
}

然后可以将此类型为T的表达式(在这种情况下为Divergence对象类型)传递给标准LINQ func.Invoke运算符(参见OrderBy),我也可以在其中传递自定义{ {1}} IComparer喜欢这样:

AlphanumComparator

这涉及更多的工作,但以我想要的方式以通用的方式解决了问题。