作者:l625208058
鏈接:https://www.jianshu.com/p/cd1be6652570
先 F12 看下 List.Sort() 方法:
1 public void Sort(int index, int count, IComparer<T> comparer); //指定范圍排序 2 public void Sort(Comparison<T> comparison); //Comparison<T>其實就是個委托 3 public void Sort(); //使用默認排序 4 public void Sort(IComparer<T> comparer); //使用一個自定義排序者
一. Comparison<T>
1 public delegate int Comparison<in T>(T x, T y);
這其實就是個委托,排序示例:
1 Dictionary<string, int> dic = new Dictionary<string, int>(); 2 dic.Add("index.html", 50); 3 dic.Add("product.html", 13); 4 dic.Add("aboutus.html", 4); 5 dic.Add("online.aspx", 22); 6 dic.Add("news.aspx", 18); 7 8 public static int h1(KeyValuePair<string, int> s1, KeyValuePair<string, int> s2) 9 { 10 return s2.Value.CompareTo(s1.Value); 11 } 12 13 //第一種,使用預先定義的靜態方法 14 List<KeyValuePair<string, int>> list1 = new List<KeyValuePair<string, int>>(dic); 15 list1.Sort(h1); 16 17 //第二種,使用Dictionary<string, int> dic = new Dictionary<string, int>(); 18 dic.Add("index.html", 50); 19 dic.Add("product.html", 13); 20 dic.Add("aboutus.html", 4); 21 dic.Add("online.aspx", 22); 22 dic.Add("news.aspx", 18); 23 24 public static int h1(KeyValuePair<string, int> s1, KeyValuePair<string, int> s2) 25 { 26 return s2.Value.CompareTo(s1.Value); 27 } 28 29 //第一種,使用預先定義的靜態方法 30 List<KeyValuePair<string, int>> list1 = new List<KeyValuePair<string, int>>(dic); 31 list1.Sort(h1); 32 33 //第二種,使用匿名方法 34 List<KeyValuePair<string, int>> list2 = new List<KeyValuePair<string, int>>(dic); 35 list1.Sort(delegate (KeyValuePair<string, int> s1, KeyValuePair<string, int> s2) 36 { 37 return s2.Value.CompareTo(s1.Value); 38 }); 39 40 //第三種,使用 lambda 表達式 41 List<KeyValuePair<string, int>> list3 = new List<KeyValuePair<string, int>>(dic); 42 list2.Sort((s1, s2) => { return s1.Value.CompareTo(s2.Value); });
二. Comparer<T>、IComparer<T>
1. 概念:為 IComparer<T> 泛型接口實現提供的基類。
1 public abstract class Comparer<T> : IComparer, IComparer<T> 2 { 3 protected Comparer(); 4 public static Comparer<T> Default { get; } 5 public static Comparer<T> Create(Comparison<T> comparison); 6 public abstract int Compare(T x, T y); 7 }
2. Comparer<T>和 IComparer<T>的區別:
-
- Comparer<T>是類,並提供了默認比較器,也就是說,如果需要自定義默認比較器,需要自行實現IComparer<T>接口
- 使用Comparer<T>.Default來獲取默認比較器
- IComparer<T> 就是提供一個統一的比較接口,而Comparer<T>就是官方為你提供的一個抽象實現類,具體還是得要你重寫實現
三. IComparable<T>
自己設計的模型類需要比較,可繼承此接口,實現后就可以直接使用排序
接口類:
1 public interface IComparable<in T> 2 { 3 int CompareTo(T other); 4 }
四.Comparer<T> Class、IComparer<T>、IComparable<T>官方案例
1 class Test 2 { 3 static void Main(string[] args) 4 { 5 List<Box> Boxes = new List<Box>(); 6 Boxes.Add(new Box(4, 20, 14)); 7 Boxes.Add(new Box(12, 12, 12)); 8 Boxes.Add(new Box(8, 20, 10)); 9 Boxes.Add(new Box(6, 10, 2)); 10 Boxes.Add(new Box(2, 8, 4)); 11 Boxes.Add(new Box(2, 6, 8)); 12 Boxes.Add(new Box(4, 12, 20)); 13 Boxes.Add(new Box(18, 10, 4)); 14 Boxes.Add(new Box(24, 4, 18)); 15 Boxes.Add(new Box(10, 4, 16)); 16 Boxes.Add(new Box(10, 2, 10)); 17 Boxes.Add(new Box(6, 18, 2)); 18 Boxes.Add(new Box(8, 12, 4)); 19 Boxes.Add(new Box(12, 10, 8)); 20 Boxes.Add(new Box(14, 6, 6)); 21 Boxes.Add(new Box(16, 6, 16)); 22 Boxes.Add(new Box(2, 8, 12)); 23 Boxes.Add(new Box(4, 24, 8)); 24 Boxes.Add(new Box(8, 6, 20)); 25 Boxes.Add(new Box(18, 18, 12)); 26 27 //使用繼承了Comparer<T>的比較器,進行排序。里面覆寫了Compare(T a,T b)方法 28 Boxes.Sort(new BoxLengthFirst()); 29 30 foreach (Box bx in Boxes) 31 { 32 Console.WriteLine("{0}\t{1}\t{2}", 33 bx.Height.ToString(), bx.Length.ToString(), 34 bx.Width.ToString()); 35 } 36 37 Console.WriteLine("==============="); 38 39 //獲取默認比較器 40 Comparer<Box> defComp = Comparer<Box>.Default; 41 42 // Calling Boxes.Sort() with no parameter 43 // is the same as calling Boxs.Sort(defComp) 44 // because they are both using the default comparer. 45 // 等於調用Boxs.Sort(defComp); 46 Boxes.Sort(); 47 48 foreach (Box bx in Boxes) 49 { 50 //輸出高、長、寬 51 Console.WriteLine("{0}\t{1}\t{2}", 52 bx.Height.ToString(), bx.Length.ToString(), 53 bx.Width.ToString()); 54 } 55 56 // This explicit interface implementation 57 // compares first by the length. 58 // Returns -1 because the length of BoxA 59 // is less than the length of BoxB. 60 BoxLengthFirst LengthFirst = new BoxLengthFirst(); 61 62 Comparer<Box> bc = (Comparer<Box>)LengthFirst; 63 64 Box BoxA = new Box(2, 6, 8); 65 Box BoxB = new Box(10, 12, 14); 66 int x = LengthFirst.Compare(BoxA, BoxB); 67 Console.WriteLine(); 68 Console.WriteLine(x.ToString()); 69 70 Console.ReadLine(); 71 } 72 } 73 public class BoxLengthFirst : Comparer<Box> 74 { 75 //父類抽象方法 Compare 76 // Compares by Length, Height, and Width. 77 public override int Compare(Box x, Box y) 78 { 79 if (x.Length.CompareTo(y.Length) != 0) 80 { 81 return x.Length.CompareTo(y.Length); 82 } 83 else if (x.Height.CompareTo(y.Height) != 0) 84 { 85 return x.Height.CompareTo(y.Height); 86 } 87 else if (x.Width.CompareTo(y.Width) != 0) 88 { 89 return x.Width.CompareTo(y.Width); 90 } 91 else 92 { 93 return 0; 94 } 95 } 96 97 } 98 99 100 // This class is not demonstrated in the Main method 101 // and is provided only to show how to implement 102 // the interface. It is recommended to derive 103 // from Comparer<T> instead of implementing IComparer<T>. 104 105 //沒有在Main方法里演示,推薦使用繼承Comparer<T>的方法。 106 public class BoxComp : IComparer<Box> 107 { 108 // Compares by Height, Length, and Width. 109 public int Compare(Box x, Box y) 110 { 111 if (x.Height.CompareTo(y.Height) != 0) 112 { 113 return x.Height.CompareTo(y.Height); 114 } 115 else if (x.Length.CompareTo(y.Length) != 0) 116 { 117 return x.Length.CompareTo(y.Length); 118 } 119 else if (x.Width.CompareTo(y.Width) != 0) 120 { 121 return x.Width.CompareTo(y.Width); 122 } 123 else 124 { 125 return 0; 126 } 127 } 128 } 129 130 public class Box : IComparable<Box> 131 { 132 public Box(int h, int l, int w) 133 { 134 this.Height = h; 135 this.Length = l; 136 this.Width = w; 137 } 138 public int Height { get; private set; } 139 public int Length { get; private set; } 140 public int Width { get; private set; } 141 142 public int CompareTo(Box other) 143 { 144 // Compares Height, Length, and Width. 145 if (this.Height.CompareTo(other.Height) != 0) 146 { 147 return this.Height.CompareTo(other.Height); 148 } 149 else if (this.Length.CompareTo(other.Length) != 0) 150 { 151 return this.Length.CompareTo(other.Length); 152 } 153 else if (this.Width.CompareTo(other.Width) != 0) 154 { 155 return this.Width.CompareTo(other.Width); 156 } 157 else 158 { 159 return 0; 160 } 161 } 162 }
五. Comparison<T>、 Comparer<T>、 System.IComparable、IComparable<T>的區別
-
Comparison<T>,繼承委托。開發人員可以在外部寫個用於比較大小的函數,然后作為 Comparison<T>類型的參數傳入,進行比較,非常方便。
-
派生自 Comparer<T> 類和實現 System.IComparable 接口之間的差異如下:
-
若要指定默認情況下(Default獲取)應如何比較兩個對象,請在類中實現 System.IComparable 接口。 這可確保排序操作將使用您提供的默認比較代碼。
-
若要定義要使用的比較器而不是默認比較器,請從 Comparer<T> 類派生。 然后,您可以在采用比較器作為參數的排序操作中使用此比較器。
- Default 屬性返回的對象使用 System.IComparable<T> 泛型接口來比較兩個對象。 如果類型 T 未實現 System.IComparable<T> 泛型接口,Default 屬性返回使用 System.IComparable 接口的 Comparer<T>。