- A+
所属分类:.NET技术
一 创建对象时考虑实现比较器
假设有这样的场景,有一个40个人的学生列表,业务中需针对学生的成绩来进行排序。
可以考虑用IComparable接口和ICompare接口实现:
class Program { static void Main(string[] args) { var stus = new List<Student>(); stus.Add(new Student() { Name = "zhangsan", EnglishGrades = 80.5, MathGrades = 90 }); stus.Add(new Student() { Name = "lisi", EnglishGrades = 74, MathGrades = 91 }); stus.Add(new Student() { Name = "wangwu", EnglishGrades = 94, MathGrades = 85.5 }); stus.Add(new Student() { Name = "zhaoliu", EnglishGrades = 88.5, MathGrades = 86 }); stus.Sort(); Console.WriteLine("使用默认比较器排序:"); foreach (var stu in stus) { Console.WriteLine($"Name:{stu.Name},tEnglish:{stu.EnglishGrades},tMath:{stu.MathGrades}"); } stus.Sort(new MathComparer()); Console.WriteLine("使用自定义比较器排序:"); foreach (var stu in stus) { Console.WriteLine($"Name:{stu.Name},tEnglish:{stu.EnglishGrades},tMath:{stu.MathGrades}"); } Console.ReadLine(); } } //Student通过IComparable接口,实现默认比较器 class Student : IComparable<Student> { public string Name { get; set; } public double EnglishGrades { get; set; } public double MathGrades { get; set; } public int CompareTo(Student stu) { if (EnglishGrades > stu.EnglishGrades) { return 1; } else if (EnglishGrades == stu.EnglishGrades) { return 0; } else { return -1; } //return EnglishGrades.CompareTo(stu.EnglishGrades); double类型的默认比较方法 } } //通过IComparer接口实现自定义的比较器 class MathComparer : IComparer<Student> { public int Compare(Student x, Student y) { return x.MathGrades.CompareTo(y.MathGrades); } }
输出:
使用默认比较器排序: Name:lisi, English:74, Math:91 Name:zhangsan, English:80.5, Math:90 Name:zhaoliu, English:88.5, Math:86 Name:wangwu, English:94, Math:85.5 使用自定义比较器排序: Name:wangwu, English:94, Math:85.5 Name:zhaoliu, English:88.5, Math:86 Name:zhangsan, English:80.5, Math:90 Name:lisi, English:74, Math:91
二 使用LINQ取代集合中的比较器
上述的方法实现的排序存在2个问题:
- 可扩展性太低,如果存在新的排序要求,就必须实现新的比较器;
- 对代码的侵入性太高,为类型继承了接口,新增了方法。
LINQ提供了类似于SQL的语法来实现遍历、筛选和投影集合的强大功能,可以实现上述的排序要求。
static void Main(string[] args) { var stus = new List<Student>(); stus.Add(new Student() { Name = "zhangsan", EnglishGrades = 80.5, MathGrades = 90 }); stus.Add(new Student() { Name = "lisi", EnglishGrades = 74, MathGrades = 91 }); stus.Add(new Student() { Name = "wangwu", EnglishGrades = 94, MathGrades = 85.5 }); stus.Add(new Student() { Name = "zhaoliu", EnglishGrades = 88.5, MathGrades = 86 }); var orderByStus = from s in stus orderby s.EnglishGrades select s; //orderByStus = stus.OrderBy(s => s.EnglishGrades); foreach (var stu in orderByStus) { Console.WriteLine($"Name:{stu.Name},tEnglish:{stu.EnglishGrades},tMath:{stu.MathGrades}"); } Console.WriteLine(); orderByStus = from s in stus orderby s.MathGrades select s; //orderByStus = stus.OrderBy(s => s.MathGrades); foreach (var stu in orderByStus) { Console.WriteLine($"Name:{stu.Name},tEnglish:{stu.EnglishGrades},tMath:{stu.MathGrades}"); } Console.ReadLine(); }
LINQ此功能的实现本身是借助于FCL泛型集合的比较器、迭代器和索引器。LINQ封装了这些功能,让我们使用更加方便。
在命名空间System.Linq下的Enumerable方法中为泛型集合提供了很多扩展方法。
如排序中使用到的OrderBy方法:
public static IOrderedEnumerable<TSource> OrderBy<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector);
它为继承了IEnumerable<T>接口的集合提供排序的功能。