【原创+散分】逐步为对象集合构建一个通用的按指定属性排序的方法解决办法
【原创+散分】逐步为对象集合构建一个通用的按指定属性排序的方法
有时候我们需要对集合中的自定义对象进行排序,以最原始的 System.Array 为例,如
类 Person 的定义为:
可能会需要根据 Id、Name 及 Birthday 进行排序。在 .NET 中,自定义对象数组排序最常见的实现方式是在对象中实现 IComparable 接口,然后调用 Array.Sort(array) 静态方法,显然,在上述情形下,这不是一个好的解决办法。其实 .NET 提供了一个泛型的 Sort() 静态方法,可以根据指定的谓词函数进行排序,其定义如下:
按照定义,我们先定义一个谓词函数:
然后在排序时,如下调用:
使用语句输出结果:
可以看到 Person 数组已经按照 Id 排序了。因为 .NET 内置的类型大多都实现了 IComparable 接口,包括值类型,所以上面的谓词函数可以简化为:
虽然这个函数写起来很简单,但是对每个需要进行排序的属性都写一个函数,也挺麻烦,幸好 .NET 2.0 提供了匿名委托,不用再单独定义函数了:
简单了许多,如果是 .NET 3.5,可以用 Lamda 表达式进一步简化:
在实际应用开发中,从性能和易用性上来说,到这一步大多数情形下已经足够。下面的部分可能有过度设计的嫌疑,但这里主要是研究 .NET 一些特性的使用,所以我们继续往下。
能否直接返回一个委托,使我们不必关心 Person 类的具体属性比较,而直接根据属性进行排序呢?答案是肯定的。为 Person 类添加一个静态方法:
排序时,可以这样调用:
有时候我们需要对集合中的自定义对象进行排序,以最原始的 System.Array 为例,如
- C# code
Person[] people = new Person[]{ new Person(3, "Andy", new DateTime(1982, 10, 3)), new Person(1, "Tom", new DateTime(1993, 2, 10)), new Person(2, "Jerry", new DateTime(1988, 4, 23)) };
类 Person 的定义为:
- C# code
class Person { public int Id { get; set; } public string Name { get; set; } public DateTime Birthday { get; set; } public Person(int id, string name, DateTime birthday) { Id = id; Name = name; Birthday = birthday; } public override string ToString() { return String.Format("Id: {0,-6}Name: {1,-20}Birthday: {2:yyyy-MM-dd}", Id, Name, Birthday); } }
可能会需要根据 Id、Name 及 Birthday 进行排序。在 .NET 中,自定义对象数组排序最常见的实现方式是在对象中实现 IComparable 接口,然后调用 Array.Sort(array) 静态方法,显然,在上述情形下,这不是一个好的解决办法。其实 .NET 提供了一个泛型的 Sort() 静态方法,可以根据指定的谓词函数进行排序,其定义如下:
- C# code
public static void Sort<T>( T[] array, Comparison<T> comparison )
按照定义,我们先定义一个谓词函数:
- C# code
static int CompareById(Person first, Person second) { if (first.Id > second.Id) return 1; if (first.Id == second.Id) return 0; return -1; }
然后在排序时,如下调用:
- C# code
Array.Sort(people, new Comparison<Person>(CompareById));
使用语句输出结果:
- C# code
foreach (Person p in people) Console.WriteLine(p);
可以看到 Person 数组已经按照 Id 排序了。因为 .NET 内置的类型大多都实现了 IComparable 接口,包括值类型,所以上面的谓词函数可以简化为:
- C# code
static int CompareById(Person first, Person second) { return first.Id.CompareTo(second.Id); }
虽然这个函数写起来很简单,但是对每个需要进行排序的属性都写一个函数,也挺麻烦,幸好 .NET 2.0 提供了匿名委托,不用再单独定义函数了:
- C# code
Array.Sort(people, delegate(Person first, Person second){ return first.Id.CompareTo(second.Id); });
简单了许多,如果是 .NET 3.5,可以用 Lamda 表达式进一步简化:
- C# code
Array.Sort(people, (first, second) => first.Id.CompareTo(second.Id));
在实际应用开发中,从性能和易用性上来说,到这一步大多数情形下已经足够。下面的部分可能有过度设计的嫌疑,但这里主要是研究 .NET 一些特性的使用,所以我们继续往下。
能否直接返回一个委托,使我们不必关心 Person 类的具体属性比较,而直接根据属性进行排序呢?答案是肯定的。为 Person 类添加一个静态方法:
- C# code
public static Comparison<Person> CompareByProperty(string name) { switch (name) { case "Id": return (first, second) => first.Id.CompareTo(second.Id); case "Name": return (first, second) => first.Name.CompareTo(second.Name); case "Birthday": return (first, second) => first.Birthday.CompareTo(second.Birthday); default: throw new Exception("属性 " + name + " 不存在。"); } }
排序时,可以这样调用: