问题
After a good dose of Googling and trying some things and not finding/getting the desired result I decided to post this question.
I have a custom made OrderBy
extension method and now when performing the OrderBy
operation I'd like to pass an AlphanumComparator like this:
return divergences.OrderBy(sort, new AlphanumComparator());
Here's the extension method:
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);
}
See the comment in the code where I think I should pass the IComparer
... how could I approach this?
回答1:
I had to approach this differently.
I was trying to create a generic OrderBy
to be used with MvcContrib Grid, but passing the IComparer to that custom OrderBy
expression did not work as I imagined it would work.
So I created this helper that receives a string in dot notation like Element1.Standard.Chapter.Manual.Name
and then returns an 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();
}
This expression typed to T (in this case Divergence
object type) can then be passed (see func.Invoke
) to the standard LINQ OrderBy
operator where I can also pass the custom IComparer
AlphanumComparator
like this:
if (sort.Column.Contains("Index"))
{
var func = Helpers.ExtensionMethods.CreateSelectorExpression<Divergence>(sort.Column);
if (sort.Direction == SortDirection.Ascending)
{
return divergences.OrderBy(func, new AlphanumComparator());
}
else
{
return divergences.OrderByDescending(func, new AlphanumComparator());
}
}
This involved a little bit more work but solved the problem in a generic fashion the way I wanted it to be.
来源:https://stackoverflow.com/questions/17796800/passing-an-icomparer-parameter-to-custom-linq-orderby-extension-method