集合根据不同字段名称动态实现排序

  1 using System;
  2 using System.Collections.Generic;
  3 using System.Linq;
  4 using System.Linq.Expressions;
  5 using System.Reflection;
  6 using System.Security.Cryptography.X509Certificates;
  7 using System.Text;
  8 using System.Threading.Tasks;
  9 
 10 namespace System.Collections.Generic
 11 {
 12     public static class IEnumerableExtension
 13     {
 14         /// <summary>
 15         /// 排序
 16         /// 动态生成linq表达式,并手动调用排序方法OrderBy、OrderByDescending
 17         /// </summary>
 18         /// <typeparam name="T">实体类型</typeparam>
 19         /// <param name="source">源数据集合</param>
 20         /// <param name="sort">排序字段 例如:Id asc;Name desc</param>
 21         /// <returns></returns>
 22         /// <exception cref="ArgumentNullException">源数据集合不能为空</exception>
 23         /// <exception cref="InvalidOperationException">排序字段必须是实体属性名称</exception>
 24         public static IEnumerable<T> ApplySort<T>(this IEnumerable<T> source, string sort) where T : class, new()
 25         {
 26             if (source == null)
 27                 throw new ArgumentNullException(nameof(source));
 28 
 29             if (string.IsNullOrWhiteSpace(sort))
 30                 return source;
 31 
 32             var type = typeof(T);
 33             var sortVector = sort.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries);
 34             /*
 35              * 注意:要使BindingFlags.IgnoreCase生效,必须搭配BindingFlags.Instance和BindingFlags.Public一起使用
 36              */
 37             var property = type.GetProperty(sortVector[0], BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase) ?? throw new InvalidOperationException("unknown sort field.");
 38             var parameter = Expression.Parameter(type, "x");
 39             var propertyAccess = Expression.MakeMemberAccess(parameter, property);
 40             var orderByExp = Expression.Lambda(propertyAccess, parameter);
 41 
 42             var queryable = source.AsQueryable();
 43             MethodCallExpression resultExp = Expression.Call(typeof(Queryable),
 44              sortVector.Length == 1 ? "OrderBy" : "asc".Equals(sortVector[1]) ? "OrderBy" : "OrderByDescending",
 45              new Type[] { type, property.PropertyType },
 46              queryable.Expression,
 47              Expression.Quote(orderByExp));
 48 
 49             var sortedQuery = queryable.Provider.CreateQuery(resultExp);
 50             var sortedList = sortedQuery.Cast<T>().ToList();
 51             return sortedList;
 52         }
 53 
 54         /// <summary>
 55         /// 排序
 56         /// 利用Linq本身的OrderBy、OrderByDescending方法进行排序,根据字段名称反射获取属性值
 57         /// </summary>
 58         /// <typeparam name="T">实体类型</typeparam>
 59         /// <param name="source">源数据集合</param>
 60         /// <param name="sort">排序字段 例如:Id asc;Name des</param>
 61         /// <returns></returns>
 62         /// <exception cref="ArgumentNullException">源数据集合不能为空</exception>
 63         /// <exception cref="InvalidOperationException">排序字段必须是实体属性名称</exception>
 64         public static IEnumerable<T> ApplyLinqSort<T>(this IEnumerable<T> source, string sort) where T : class, new()
 65         {
 66             if (source == null)
 67                 throw new ArgumentNullException(nameof(source));
 68 
 69             if (string.IsNullOrWhiteSpace(sort))
 70                 return source;
 71 
 72             var sortVector = sort.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries);
 73             string sortField = sortVector[0], sortFlag = sortVector.Length > 1 ? sortVector[1] : "asc";
 74             return "asc".Equals(sortFlag) ?
 75                        source.OrderBy(o => o?.GetType().GetProperty(sortField, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)?.GetValue(o) ?? throw new InvalidOperationException("unknown sort field.")) :
 76                        source.OrderByDescending(o => o?.GetType().GetProperty(sortField, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase)?.GetValue(o) ?? throw new InvalidOperationException("unknown sort field."));
 77         }
 78 
 79         /// <summary>
 80         /// 排序
 81         /// 利用List集合的Sort方法进行排序
 82         /// </summary>
 83         /// <typeparam name="T">实体类型</typeparam>
 84         /// <param name="source">源数据集合</param>
 85         /// <param name="sort">排序字段 例如:Id asc;Name des</param>
 86         /// <returns></returns>
 87         /// <exception cref="ArgumentNullException">源数据集合不能为空</exception>
 88         /// <exception cref="InvalidOperationException">排序字段必须是实体属性名称</exception>
 89         public static IEnumerable<T> ApplyReflectSort<T>(this IEnumerable<T> source, string sort) where T : class, new()
 90         {
 91             if (source == null)
 92                 throw new ArgumentNullException(nameof(source));
 93 
 94             if (string.IsNullOrWhiteSpace(sort))
 95                 return source;
 96 
 97             var sortVector = sort.ToLower().Split(' ', StringSplitOptions.RemoveEmptyEntries);
 98             string sortField = sortVector[0], sortFlag = sortVector.Length > 1 ? sortVector[1] : "asc";
 99             var type = typeof(T);
100             PropertyInfo property = type.GetProperty(sortField, BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase) ?? throw new InvalidOperationException("unknown sort field.");
101             var list = source.ToList();
102             list.Sort((T before, T after) =>
103             {
104                 return "asc".Equals(sortFlag) ?
105                 property.GetValue(before).CompareTo(property.GetValue(after)) :
106                 property.GetValue(after).CompareTo(property.GetValue(before));
107             });
108             return list;
109         }
110 
111         static int CompareTo(this object? source, object? value)
112         {
113             if (source == null || value == null)
114                 return 0;
115 
116             var sTypeName = source.GetType().Name.ToLower();
117             var cTypeName = value.GetType().Name.ToLower();
118             if (sTypeName != cTypeName)
119                 throw new InvalidOperationException("the type of them is different,they can't be compared.");
120 
121             return sTypeName switch
122             {
123                 "int16" => Convert.ToInt16(source).CompareTo(Convert.ToInt16(value)),
124                 "int" or "int32" => Convert.ToInt32(source).CompareTo(Convert.ToInt32(value)),
125                 "int64" => Convert.ToInt64(source).CompareTo(Convert.ToInt64(value)),
126                 "double" => Convert.ToDouble(source).CompareTo(Convert.ToDouble(value)),
127                 "single" => Convert.ToSingle(source).CompareTo(Convert.ToSingle(value)),
128                 "decimal" => Convert.ToDecimal(source).CompareTo(Convert.ToDecimal(value)),
129                 "string" => Convert.ToString(source)?.CompareTo(Convert.ToString(value)) ?? 0,
130                 "datetime" => Convert.ToDateTime(source).CompareTo(Convert.ToDateTime(value)),
131                 _ => throw new NotImplementedException("unknown compare type."),
132             };
133         }
134     }
135 }

 

posted @ 2024-07-19 10:20  DreamerSix  阅读(1)  评论(0编辑  收藏  举报