改善C#程序的方法-(3)比较器和LINQ排序

  • 改善C#程序的方法-(3)比较器和LINQ排序已关闭评论
  • 171 次浏览
  • A+
所属分类:.NET技术
摘要

假设有这样的场景,有一个40个人的学生列表,业务中需针对学生的成绩来进行排序。


一 创建对象时考虑实现比较器

假设有这样的场景,有一个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>接口的集合提供排序的功能。