Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static class OrderByExtensions
- {
- /// <summary>
- /// Sorts the elements of a sequence in according to a collection of keys.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
- /// <param name="source">A sequence of values to order.</param>
- /// <param name="keysInfo">A collection of order by key information.</param>
- /// <returns>An <see cref="IOrderedQueryable{T}"/> whose elements are sorted according to the keys information.</returns>
- /// <exception cref="ArgumentNullException"><paramref name="source"/> is <c>null</c></exception>
- /// <exception cref="ArgumentException">
- /// <paramref name="keysInfo"/> is <c>null</c> or empty
- /// -or-
- /// <paramref name="keysInfo"/> contains a key that is not found on type <typeparamref name="TSource"/>.
- /// </exception>
- public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, params OrderByKeyInfo[] keysInfo)
- {
- if (source == null)
- throw new ArgumentNullException("source");
- if (keysInfo == null || keysInfo.Length == 0)
- throw new ArgumentException("Key selector cannot be null or empty.", "source");
- // Good candidate to be cached
- var keySelectorMapping = BuildKeySelectorMapping<TSource>();
- var unknownKeys = keysInfo.Where(prop => !keySelectorMapping.ContainsKey(prop.KeyName)).Select(prop => prop.KeyName);
- if (unknownKeys.Any())
- throw new ArgumentException(string.Format("Unable to find one or more keys by name. Type: {0}, Keys: {1}",
- typeof(TSource), string.Join(", ", unknownKeys)), "keysInfo");
- var firstKeyInfo = keysInfo.First();
- var keySelector = keySelectorMapping[firstKeyInfo.KeyName];
- var orderedSource = firstKeyInfo.Direction == OrderByDirection.Ascending ?
- source.OrderBy(keySelector) :
- source.OrderByDescending(keySelector);
- foreach (var keyInfo in keysInfo)
- {
- // Skip the first because already sorted by the first
- if (keyInfo == firstKeyInfo)
- continue;
- keySelector = keySelectorMapping[keyInfo.KeyName];
- orderedSource = keyInfo.Direction == OrderByDirection.Ascending ?
- orderedSource.ThenBy(keySelector) :
- orderedSource.ThenByDescending(keySelector);
- }
- return orderedSource;
- }
- /// <summary>
- /// Sorts the elements of a sequence in according to a collection of keys.
- /// </summary>
- /// <typeparam name="TSource">The type of the elements of <paramref name="source"/>.</typeparam>
- /// <param name="source">A sequence of values to order.</param>
- /// <param name="keysInfo">A collection of order by key information.</param>
- /// <returns>An <see cref="IEnumerable{T}"/> whose elements are sorted according to the keys information.</returns>
- /// <exception cref="ArgumentNullException"><paramref name="source"/> is <c>null</c></exception>
- /// <exception cref="ArgumentException">
- /// <paramref name="keysInfo"/> is <c>null</c> or empty
- /// -or-
- /// <paramref name="keysInfo"/> contains a key that is not found on type <typeparamref name="TSource"/>.
- /// </exception>
- public static IEnumerable<TSource> OrderBy<TSource>(this IEnumerable<TSource> source, params OrderByKeyInfo[] keysInfo)
- {
- return source.AsQueryable().OrderBy(keysInfo).ToList();
- }
- /// <summary>
- /// Builds a mapping from the key name to a function to extract a key from an element.
- /// </summary>
- /// <typeparam name="TSource">The type of the source element.</typeparam>
- /// <returns>A mapping from a key name to a lambda key selector.</returns>
- private static Dictionary<string, Expression<Func<TSource, object>>> BuildKeySelectorMapping<TSource>()
- {
- var sourceType = typeof(TSource);
- var properties = sourceType.GetProperties();
- var keySelectorMapping = new Dictionary<string, Expression<Func<TSource, object>>>();
- foreach (var propertyInfo in properties)
- {
- var localScopePropertyInfo = propertyInfo;
- var name = propertyInfo.Name;
- Expression<Func<TSource, object>> keySelector = source => localScopePropertyInfo.GetValue(source);
- keySelectorMapping.Add(name, keySelector);
- }
- return keySelectorMapping;
- }
- }
- public class OrderByKeyInfo
- {
- /// <summary>
- /// Initializes a new instance of the <see cref="OrderByKeyInfo"/> class.
- /// </summary>
- /// <param name="keyName">Name of the key.</param>
- /// <param name="direction">The direction to order by.</param>
- public OrderByKeyInfo(string keyName, OrderByDirection direction)
- {
- KeyName = keyName;
- Direction = direction;
- }
- public string KeyName { get; private set; }
- public OrderByDirection Direction { get; private set; }
- }
- public enum OrderByDirection
- {
- Ascending,
- Descending
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement