集合根据不同字段名称动态实现排序
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 }