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 }