背景:
工作中遇到这种排序场景,就不能单一使用System.Linq.Enumerable 中的扩展方法 OrderBy,OrderByDescending 排序方式了。
实现该需求有不同的方式 记录一下:
测试代码:
public class Student { public string Name { get; set; } public int Age { get; set; } public int Height { get; set; } public int Weight { get; set; } public int Score { get; set; } public override string ToString() { return nameof(Name) + ":" + Name + "," + nameof(Age) + ":" + Age + "," + nameof(Height) + ":" + Height + "," + nameof(Weight) + ":" + Weight + "," + nameof(Score) + ":" + Score; } }
List<Student> list = new List<Student> { new Student{ Name = "Bob",Age = 29,Height = 180,Weight = 60,Score = 100}, new Student{ Name = "Foo",Age = 25,Height = 176,Weight = 67,Score = 89}, new Student{ Name = "Jam",Age = 25,Height = 176,Weight = 67,Score = 99}, new Student{ Name = "Alice",Age = 31,Height = 169,Weight = 66,Score = 87}, new Student{ Name = "Nura",Age = 31,Height = 160,Weight = 70,Score = 78} };
1:使用内置的排序方式,硬编码不同的字段
命名空间:System.Linq 下 有 ThenByDescending ,Enumerable.ThenBy 扩展方法 用于在 调用 OrderBy OrderByDescending之后调用,按升序,降序 对序列中的元素执行后续排序。
public static System.Linq.IOrderedEnumerable<TSource> ThenBy<TSource,TKey> (this System.Linq.IOrderedEnumerable<TSource> source, Func<TSource,TKey> keySelector);
Console.WriteLine("排序前:"); foreach (var item in list) Console.WriteLine(item.ToString()); //测试升序排列:Age 排序 当Age相同 Height排序 当Height相同 Weight排序 当Weight相同 Score排序…… Console.WriteLine(); Console.WriteLine("System.Linq.Enumerable 中的扩展 内置排序:"); list = list.OrderByDescending(c => c.Age).ThenBy(c => c.Height).ThenBy(c => c.Weight).ThenBy(c => c.Score).ToList(); Console.WriteLine("排序后:"); foreach (var item in list) Console.WriteLine(item.ToString());
输出如下:
2:通过实现IComparer<Student>接口 自定义排序
示例代码:
public class MyCompare : IComparer<Student> { /// <summary> /// 动态排序字段 /// </summary> public readonly string[] PropNames; public MyCompare(string[] propNames) { //PropNames = string[]{ "Age", "Height", "Weight", "Score" }; PropNames = propNames; } public int Compare(Student x, Student y) { int i = PropNames.Length; return InnerCompare(x, y, i); } private int InnerCompare(Student x, Student y, int i) { for (int j = 0; j < i; j++) { var propName = PropNames[j]; var prop = typeof(Student).GetProperty(propName); var xValue = prop.GetValue(x); var yValue = prop.GetValue(y); //当具有不同的数据类型 //if (xValue.GetType() == typeof(int)) int xCurrentPropValue = Convert.ToInt32(xValue); int yCurrentPropValue = Convert.ToInt32(yValue); if (xCurrentPropValue != yCurrentPropValue) { return xCurrentPropValue.CompareTo(yCurrentPropValue); } else { return InnerCompare(x, y, j + 1); } } return 0; } }
输出如下:
说明:
C#中有 IComparable、IComparer接口
前者 定义通用比较方法 排序实现的最底层逻辑,后者定义排序方式 借助于IComparable接口
如示例代码中的 return xCurrentPropValue.CompareTo(yCurrentPropValue); CompareTo方法还是依赖于默认实现了的IComparable接口中的 CompareTo方法。