tisdag 19 maj 2009

Extended OrderBy

Extension methods for OrderBy and ThenBy methods, introducing two new features:
* The possibility to determine sort direction ascending/descending by passing a boolean value, rather than using a whole different method.
* The possibility to pass a string value for the property to sort by, which will be resolved using reflection

Both features may come in handy when sorting depends upon user input, such as the ability to resort a table by clicking table headers.

Courtesy of David Hedlund.

public static IOrderedEnumerable<TResult> OrderBy<TResult>(this IEnumerable<TResult> source, string propertyName)
{
   return OrderBy(source, propertyName, true);
}

public static IOrderedEnumerable<TResult> OrderByDescending<TResult>(this IEnumerable<TResult> source, string propertyName)
{
   return OrderBy(source, propertyName, false);
}

public static IOrderedEnumerable<TResult> OrderBy<TResult>(this IEnumerable<TResult> source, string propertyName, bool ascending)
{
   System.Reflection.PropertyInfo prop = typeof(TResult).GetProperty(propertyName);
   Func<TResult, object> orderBy = (i => prop.GetValue(i, null));
   return source.OrderBy(orderBy, ascending);
}

public static IOrderedEnumerable<TResult> OrderBy<TResult,TKey>(this IEnumerable<TResult> source, Func<TResult, TKey> keySelector, bool ascending)
{
   Func<Func<TResult, TKey>, IOrderedEnumerable<TResult>> orderMethod = source.OrderBy;

   if(!ascending)
      orderMethod = source.OrderByDescending;

   return orderMethod.Invoke(keySelector);
}

public static IOrderedEnumerable<TResult> ThenBy<TResult>(this IOrderedEnumerable<TResult> source, string propertyName)
{
   return ThenBy(source, propertyName, true);
}

public static IOrderedEnumerable<TResult> ThenByDescending<TResult>(this IOrderedEnumerable<TResult> source, string propertyName)
{
   return ThenBy(source, propertyName, false);
}

public static IOrderedEnumerable<TResult> ThenBy<TResult>(this IOrderedEnumerable<TResult> source, string propertyName, bool ascending)
{
   System.Reflection.PropertyInfo prop = typeof(TResult).GetProperty(propertyName);
   Func<TResult, object> orderBy = (i => prop.GetValue(i, null));
   return source.ThenBy(orderBy, ascending);
}

public static IOrderedEnumerable<TResult> ThenBy<TResult,TKey>(this IOrderedEnumerable<TResult> source, Func<TResult, TKey> keySelector, bool ascending)
{
   Func<Func<TResult, TKey>, IOrderedEnumerable<TResult>> orderMethod = source.ThenBy;

   if(!ascending)
      orderMethod = source.ThenByDescending;

   return orderMethod.Invoke(keySelector);
}