none
怎样根据输入的字符串指定对实体集合某个或某两个属性进行排序? RRS feed

  • 问题

  • 一个实体中字段很多,要为每个属性,每两个属性组合准备排序功能。对一个属性进行排序,或者对某两个属性进行排序,字段比较多的话,为所有的排序组合都写一份var query= from e in entityList  order by 类似这样的代码很麻烦。有没有这样一种方法。

    根据用户输入一个或两个的字符串,如果这些字符串与实体某些属性名相同的话,就对集合中以该属性为主进行排序,如何实现。最多字段排序就两个。

    2018年7月11日 1:46

答案

  • 你好,

    你可以参考一下下面的这个扩展。

    public static class OrderByHelper
        {
            public static IEnumerable<T> OrderBy<T>(this IEnumerable<T> enumerable, string orderBy)
            {
                return enumerable.AsQueryable().OrderBy(orderBy).AsEnumerable();
            }
    
            public static IQueryable<T> OrderBy<T>(this IQueryable<T> collection, string orderBy)
            {
                foreach (OrderByInfo orderByInfo in ParseOrderBy(orderBy))
                    collection = ApplyOrderBy<T>(collection, orderByInfo);
    
                return collection;
            }
    
            private static IQueryable<T> ApplyOrderBy<T>(IQueryable<T> collection, OrderByInfo orderByInfo)
            {
                string[] props = orderByInfo.PropertyName.Split('.');
                Type type = typeof(T);
    
                ParameterExpression arg = Expression.Parameter(type, "x");
                Expression expr = arg;
                foreach (string prop in props)
                {
                    // use reflection (not ComponentModel) to mirror LINQ
                    PropertyInfo pi = type.GetProperty(prop);
                    expr = Expression.Property(expr, pi);
                    type = pi.PropertyType;
                }
                Type delegateType = typeof(Func<,>).MakeGenericType(typeof(T), type);
                LambdaExpression lambda = Expression.Lambda(delegateType, expr, arg);
                string methodName = String.Empty;
    
                if (!orderByInfo.Initial && collection is IOrderedQueryable<T>)
                {
                    if (orderByInfo.Direction == SortDirection.Ascending)
                        methodName = "ThenBy";
                    else
                        methodName = "ThenByDescending";
                }
                else
                {
                    if (orderByInfo.Direction == SortDirection.Ascending)
                        methodName = "OrderBy";
                    else
                        methodName = "OrderByDescending";
                }
    
                //TODO: apply caching to the generic methodsinfos?
                return (IOrderedQueryable<T>)typeof(Queryable).GetMethods().Single(
                    method => method.Name == methodName
                            && method.IsGenericMethodDefinition
                            && method.GetGenericArguments().Length == 2
                            && method.GetParameters().Length == 2)
                    .MakeGenericMethod(typeof(T), type)
                    .Invoke(null, new object[] { collection, lambda });
    
            }
    
            private static IEnumerable<OrderByInfo> ParseOrderBy(string orderBy)
            {
                if (String.IsNullOrEmpty(orderBy))
                    yield break;
    
                string[] items = orderBy.Split(',');
                bool initial = true;
                foreach (string item in items)
                {
                    string[] pair = item.Trim().Split(' ');
    
                    if (pair.Length > 2)
                        throw new ArgumentException(String.Format("Invalid OrderBy string '{0}'. Order By Format: Property, Property2 ASC, Property2 DESC", item));
    
                    string prop = pair[0].Trim();
    
                    if (String.IsNullOrEmpty(prop))
                        throw new ArgumentException("Invalid Property. Order By Format: Property, Property2 ASC, Property2 DESC");
    
                    SortDirection dir = SortDirection.Ascending;
    
                    if (pair.Length == 2)
                        dir = ("desc".Equals(pair[1].Trim(), StringComparison.OrdinalIgnoreCase) ? SortDirection.Descending : SortDirection.Ascending);
    
                    yield return new OrderByInfo() { PropertyName = prop, Direction = dir, Initial = initial };
    
                    initial = false;
                }
    
            }
    
            private class OrderByInfo
            {
                public string PropertyName { get; set; }
                public SortDirection Direction { get; set; }
                public bool Initial { get; set; }
            }
    
            private enum SortDirection
            {
                Ascending = 0,
                Descending = 1
            }
        }

    #用法:

    class Program
        {
            static void Main(string[] args)
            {
                List<MyClass> list = new List<MyClass>()
                {
                    new MyClass(){ Id= 1, Name = "AAA", Address = "CCC", Age = 15},
                    new MyClass(){ Id= 2, Name = "BBB", Address = "BBB", Age = 18},
                    new MyClass(){ Id= 3, Name = "CCC", Address = "AAA", Age = 16},
                    new MyClass(){ Id= 4, Name = "DDD", Address = "FFF", Age = 7},
                    new MyClass(){ Id= 5, Name = "EEE", Address = "GGG", Age = 14}
                };
                var result = list.OrderBy("Name DESC, Age ASC").ToList();
                Console.ReadKey();
            }
        }
        public class MyClass
        {
            public int Id { get; set; }
    
            public string Name { get; set; }
    
            public string Address { get; set; }
    
            public int Age { get; set; }
        }


    Best regards,

    Zhanglong


    MSDN Community Support
    Please remember to click "Mark as Answer" the responses that resolved your issue, and to click "Unmark as Answer" if not. This can be beneficial to other community members reading this thread. If you have any compliments or complaints to MSDN Support, feel free to contact MSDNFSF@microsoft.com.

    • 已标记为答案 Trian555 2018年7月11日 5:46
    2018年7月11日 3:12
    版主