(转)逐步为对象集合构建一个通用的按指定属性排序的方法
原文:http://topic.csdn.net/u/20090407/13/371533da-f709-4f1f-bda9-b4a18060e713.html?seed=924471686
有时候我们需要对集合中的自定义对象进行排序,以最原始的 System.Array 为例,如
- 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))
};
- 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);
}
}
- public static void Sort<T>(
T[] array,
Comparison<T> comparison
)
- static int CompareById(Person first, Person second)
{
if (first.Id > second.Id)
return 1;
if (first.Id == second.Id)
return 0;
return -1;
}
- Array.Sort(people, new Comparison<Person>(CompareById));
- foreach (Person p in people)
Console.WriteLine(p);
- static int CompareById(Person first, Person second)
{
return first.Id.CompareTo(second.Id);
}
- Array.Sort(people, delegate(Person first, Person second){
return first.Id.CompareTo(second.Id);
});
- Array.Sort(people, (first, second) => first.Id.CompareTo(second.Id));
能否直接返回一个委托,使我们不必关心 Person 类的具体属性比较,而直接根据属性进行排序呢?答案是肯定的。为 Person 类添加一个静态方法:
- 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 + " 不存在。");
}
}
- Array.Sort(people, Person.CompareByProperty("Birthday"));
- public static Comparison<Person> CompareByProperty(string name)
{
Type typeOfPerson = typeof(Person);
PropertyInfo p = typeOfPerson.GetProperty(name);
if (p == null)
throw new Exception("属性 " + name + " 不存在。");
// 假定该类所有的属性均实现了接口 IComparable
return (first, second) => ((IComparable)p.GetValue(first, null)).CompareTo(p.GetValue(second, null));
}
仔细观察上面的代码,应该可以把它的应用再扩大化,而不仅限于 Person 类,而这显然是泛型的长项。当然,这样的话,不应再把这个方法放在 Person 类中,我们暂时先把它移到主程序中,稍后再为它寻找一个好的归宿,修改后的CompareByProperty 泛型方法代码如下:
- public static Comparison<T> CompareByProperty<T>(string name)
{
Type typeOfPerson = typeof(T);
PropertyInfo p = typeOfPerson.GetProperty(name);
if (p == null)
throw new Exception("属性 " + name + " 不存在。");
// 假定该类所有的属性均实现了接口 IComparable
return (first, second) => ((IComparable)p.GetValue(first, null)).CompareTo(p.GetValue(second, null));
}
- Array.Sort(people, CompareByProperty<Person>("Name"));
- static class ExtensionArray
{
public static void SortBy(this Array array, string name)
{
Type elementType = array.GetType().GetElementType();
Type bridge = typeof(Bridge<>).MakeGenericType(elementType);
MethodInfo sortMethod = bridge.GetMethod("Sort");
sortMethod.Invoke(null, new object[] { array, name });
}
private static class Bridge<T>
{
private static Comparison<T> CompareByProperty(string name) //不必再是泛型方法
{
Type typeOfPerson = typeof(T);
PropertyInfo p = typeOfPerson.GetProperty(name);
if (p == null)
throw new Exception("属性 " + name + " 不存在。");
// 假定该类所有的属性均实现了接口 IComparable
return (first, second) => ((IComparable)p.GetValue(first, null)).CompareTo(p.GetValue(second, null));
}
public static void Sort(Array array, string name)
{
Array.Sort((T[])array, CompareByProperty(name));
}
}
}
现在按属性排序只需这样调用:
- people.SortBy("Birthday");