Sunday, January 30, 2011

C# - Elegant Sorting and Paging Solution

Paging is so simple that it doesn't warrants a discussion anymore:

results.Skip(page.Index).Take(page.NoOfItems)

Sorting is still tricky; I have a simple utility for it. Utility would allow to sort any object collection on any property defined in type safe way.

Usage:

1. Sorting:
var orderedResults = SorterUtility.Sort(viewModel, sortColumn, sortDirection);

2. Generating sort column delegate type safely:
sortColumn = SorterUtility.GetPropertyName<ViewModel>(x => x.Description)

Utility Code:

public class SorterUtility
    {
      
        public static IEnumerable<T> Sort<T>(IEnumerable<T> list, string sortColumn, SortDirection direction)
        {
            return direction == SortDirection.Ascending
                       ? list.ToList().OrderBy(CreateSortField<T>(sortColumn))
                       : list.ToList().OrderByDescending(CreateSortField<T>(sortColumn));
        }


        public static string GetPropertyName<T>(Expression<Func<T, object>> expression)
        {
            MemberExpression memberExpression = null;
            if (expression.Body.NodeType == ExpressionType.Convert)
            {
                var convert = expression.Body as UnaryExpression;
                if (convert != null)
                {
                    memberExpression = convert.Operand as MemberExpression;
                }
            }
            return memberExpression == null
                       ? ExpressionHelper.GetExpressionText(expression)
                       : memberExpression.Member.Name;
        }

private static Func<T, object> CreateSortField<T>(string fieldName)
        {
            //returns m => m.FieldName where M is the type & FieldName is a property name
            var classType = typeof (T);
            var param = Expression.Parameter(classType, "m");
            var memberInfo = classType.GetProperty(fieldName);
            var expr = Expression.MakeMemberAccess(param, memberInfo);
            var convert = Expression.Convert(expr, typeof (object));
            return Expression.Lambda<Func<T, object>>(convert, param).Compile();
        }
    }

No comments:

Post a Comment