一 創建對象時考慮實現比較器 假設有這樣的場景,有一個40個人的學生列表,業務中需針對學生的成績來進行排序。 可以考慮用IComparable介面和ICompare介面實現: class Program { static void Main(string[] args) { var stus = n ...
一 創建對象時考慮實現比較器
假設有這樣的場景,有一個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>介面的集合提供排序的功能。