【学习笔记】c#中的IComparable和IComparer
在c#中自定义类型实现比较和排序需要自定义类实现IComparable接口,需要实现一个名为CompareTo的方法,返回值为int唯一参数为object。
1.创建一个员工类包含Id Name Salary三个属性 继承自IComparable接口并实现CompareTo方法
1 using System; 2 using System.Collections; 3 using System.Collections.Generic; 4 using System.Linq; 5 using System.Text; 6 using System.Threading.Tasks; 7 8 namespace IComparableTest2 { 9 class Program { 10 static void Main(string[] args) { 11 var myList = new ArrayList(); 12 myList.Add(new Employee(002, "Sam", 3000)); 13 myList.Add(new Employee(001, "Mary", 2800)); 14 myList.Add(new Employee(003, "Jick", 3800)); 15 myList.Add(new Employee(004, "July", 3200)); 16 myList.Sort(); 17 foreach (var e in myList) 18 { 19 Console.WriteLine(e.ToString()); 20 } 21 Console.ReadKey(); 22 } 23 } 24 25 class Employee : IComparable { 26 public int Id { get; set; } 27 public string Name { get; set; } 28 public int Salary { get; set; } 29 30 public Employee(int id, string name, int salary) { 31 this.Id = id; 32 this.Name = name; 33 this.Salary = salary; 34 } 35 36 public override string ToString() { 37 return "ID:" + Id + " Name:" + Name + " Salary:" + Salary; 38 } 39 40 public int CompareTo(object o) { 41 Employee others = (Employee)o; 42 if (this.Id > others.Id) 43 { 44 return 1; 45 } 46 else if (this.Id < others.Id) 47 { 48 return -1; 49 } 50 else 51 { 52 return 0; 53 } 54 } 55 } 56 }
上面的CompareTo方法对Id作比较,Employee将会以Id作为键做比较,排序时键值为Id做升序。
输出结果:
ID:1 Name:Mary Salary:2800
ID:2 Name:Sam Salary:3000
ID:3 Name:Jick Salary:3800
ID:4 Name:July Salary:3200
其实int和string等预定义类型默认实现IComparable,Id的类型是int,所以可以直接进行比较。
将上面代码中CompareTo方法改为
1 public int CompareTo(object o) { 2 Employee others = (Employee)o; 3 return this.Id.CompareTo(others.Id); 4 }
效果相同。
2.如果希望以更灵活的方式进行比较,比如以工资作为键值进行排序,就需要声明一个继承自IComparer接口的比较器。
需要实现Comprae方法,返回值为int参数为2个object作为比较对象。
示例:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using IComparerTest1; namespace IComparerTest1 { class Program { static void Main(string[] args) { var myList = new ArrayList(); myList.Add(new Employee(002, "Sam", 3000)); myList.Add(new Employee(001, "Mary", 2800)); myList.Add(new Employee(003, "Jick", 3800)); myList.Add(new Employee(004, "July", 3200)); myList.Sort(new SortBySalary()); foreach (var e in myList) { Console.WriteLine(e.ToString()); } Console.ReadKey(); } } class Employee { public int Id { get; set; } public string Name { get; set; } public int Salary { get; set; } public Employee(int id, string name, int salary) { this.Id = id; this.Name = name; this.Salary = salary; } public override string ToString() { return "ID:" + Id + " Name:" + Name + " Salary:" + Salary; } } } class SortBySalary : IComparer { public int Compare(object x, object y) { Employee ex = (Employee)x; Employee ey = (Employee)y; return ex.Salary.CompareTo(ey.Salary); }
Compare方法返回的是Salary比较的结果。
把比较器的示例作为参数传递给Sort方法,就可以实现该比较器。
输出结果:
ID:1 Name:Mary Salary:2800
ID:2 Name:Sam Salary:3000
ID:4 Name:July Salary:3200
ID:3 Name:Jick Salary:3800
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
下面是泛型IComparable<T>和IComparer<T>示例,将员工信息放进一个List<Employee>中。
IComparable<T>:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace IComparableTest3 { class Program { static void Main(string[] args) { var myList = new List<Employee>(); myList.Add(new Employee(002, "Sam", 3000)); myList.Add(new Employee(001, "Mary", 2800)); myList.Add(new Employee(003, "Jick", 3800)); myList.Add(new Employee(004, "July", 3200)); myList.Sort(); foreach (var e in myList) { Console.WriteLine(e.ToString()); } Console.ReadKey(); } } class Employee : IComparable<Employee> { public int Id { get; set; } public string Name { get; set; } public int Salary { get; set; } public Employee(int id, string name, int salary) { this.Id = id; this.Name = name; this.Salary = salary; } public override string ToString() { return "ID:" + Id + " Name:" + Name + " Salary:" + Salary; } public int CompareTo(Employee e) { return this.Id.CompareTo(e.Id); } } }
IComparer<T>:
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using IComparerTest1; namespace IComparerTest1 { class Program { static void Main(string[] args) { var myList = new List<Employee>(); myList.Add(new Employee(002, "Sam", 3000)); myList.Add(new Employee(001, "Mary", 2800)); myList.Add(new Employee(003, "Jick", 3800)); myList.Add(new Employee(004, "July", 3200)); myList.Sort(new SortBySalary()); foreach (var e in myList) { Console.WriteLine(e.ToString()); } Console.ReadKey(); } } class Employee { public int Id { get; set; } public string Name { get; set; } public int Salary { get; set; } public Employee(int id, string name, int salary) { this.Id = id; this.Name = name; this.Salary = salary; } public override string ToString() { return "ID:" + Id + " Name:" + Name + " Salary:" + Salary; } } } class SortBySalary : IComparer<Employee> { public int Compare(Employee ex,Employee ey) { return ex.Salary.CompareTo(ey.Salary); } }
使用泛型避免了之前非泛型中object对Employee类型的拆箱过程,减少了不必要的性能损失。