适用于集合项目的通用比较类
你可能还有更重要的事情要做,而不是编写繁琐的比较方法。
我一直在网上寻找一种方法来排序列表,而无需编写所有自定义的比较方法,并且在c-sharpcorner网站上找到了一篇2006年的代码,作者是一位名叫Dipend Lama的人: 使用泛型排序自定义类型集合
将代码复制到我的项目中并查看结果后,我意识到我偶尔需要一次性按多个属性进行排序。不幸的是,这个类不支持这种设计考虑,所以我不得不自己实现它。我的第一个任务是决定一种传递多个(甚至只有一个)用于搜索的属性的方式。我选择了字符串数组,因为它们在方法调用中很容易实例化。但是,如果只指定了一个属性,我希望允许程序员这样做,而无需创建字符串数组,所以我保留了原始构造函数,并对其进行重载,使其接受一个字符串数组。下一个问题稍微困难一些 - 我该如何使用所有属性来排序列表?我的解决方案归结为一种基本的编程实践 - 递归。说实话,递归并不常见。在过去的30年中,我编写了数百万行代码,并且可能只使用了大约六次递归。实际上,这很简单。我采用了原始的Compare方法
编辑 (2010/08/26) ------------- 修复了一些未转义的 <> 括号。
将代码复制到我的项目中并查看结果后,我意识到我偶尔需要一次性按多个属性进行排序。不幸的是,这个类不支持这种设计考虑,所以我不得不自己实现它。我的第一个任务是决定一种传递多个(甚至只有一个)用于搜索的属性的方式。我选择了字符串数组,因为它们在方法调用中很容易实例化。但是,如果只指定了一个属性,我希望允许程序员这样做,而无需创建字符串数组,所以我保留了原始构造函数,并对其进行重载,使其接受一个字符串数组。下一个问题稍微困难一些 - 我该如何使用所有属性来排序列表?我的解决方案归结为一种基本的编程实践 - 递归。说实话,递归并不常见。在过去的30年中,我编写了数百万行代码,并且可能只使用了大约六次递归。实际上,这很简单。我采用了原始的Compare方法
public int Compare(T x, T y) { PropertyInfo propertyInfo = typeof(T).GetProperty(sortColumn); IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null); IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null); if (sortingOrder == SortOrder.Ascending) { return (obj1.CompareTo(obj2)); } else { return (obj2.CompareTo(obj1)); } }并将其更改为如下所示
public int Compare(T x, T y) { return CompareProperty(0, x, y); } private int CompareProperty(int index, T x, T y) { int result = 0; PropertyInfo propertyInfo = typeof(T).GetProperty(propertyArray[index]); IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null); IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null); if (sortingOrder == GenericSortOrder.Ascending) { result = (obj1.CompareTo(obj2)); } else { result = (obj2.CompareTo(obj1)); } if (result == 0 && index < propertyArray.Length - 1) { index++; result = CompareProperty(index, x, y); } return result; }新方法为字符串数组中的每个属性调用自身,并且一旦比较结果不为0,我就知道它完成了,并且可以退出堆栈。这是整个代码,方便你复制/粘贴到自己的代码中。
public enum GenericSortOrder { Ascending, Descending }; public sealed class GenericComparer<T> : IComparer<T> { private GenericSortOrder sortingOrder; private string[] propertyArray = null; //------------------------------------------------------------------ public GenericSortOrder SortingOrder { get { return sortingOrder; } } //------------------------------------------------------------------ public GenericComparer(string sortColumn, GenericSortOrder sortingOrder) { if (string.IsNullOrEmpty(sortColumn)) { throw new Exception("The sortColumn parameter is null/empty"); } this.sortingOrder = sortingOrder; this.propertyArray = new string[1] {sortColumn}; } //------------------------------------------------------------------ public GenericComparer(string[] properties, GenericSortOrder order) { if (properties == null || properties.Length < 1) { throw new Exception("Properties array cannot be null/empty."); } this.sortingOrder = order; this.propertyArray = properties; } //------------------------------------------------------------------ public int Compare(T x, T y) { return CompareProperty(0, x, y); } //------------------------------------------------------------------ private int CompareProperty(int index, T x, T y) { int result = 0; PropertyInfo propertyInfo = typeof(T).GetProperty(propertyArray[index]); IComparable obj1 = (IComparable)propertyInfo.GetValue(x, null); IComparable obj2 = (IComparable)propertyInfo.GetValue(y, null); if (sortingOrder == GenericSortOrder.Ascending) { result = (obj1.CompareTo(obj2)); } else { result = (obj2.CompareTo(obj1)); } if (result == 0 && index < propertyArray.Length - 1) { index++; result = CompareProperty(index, x, y); } return result; } }用法如下所示
List<MyObject> list = new List<MyObject>(); list.Sort(new GenericCompare<MyObject>("singleProperty", GenericOrder.Descending); list.Sort(new GenericCompare<MyObject>(new string[2] {"property1", "property2"}, GenericSortOrder.Descending);必须小心,不要按过多的属性进行排序,否则你的代码将抛出堆栈溢出异常。可能还有更优雅的解决方案,如果你知道,请务必将其作为替代方案发布。编辑 =========================== 这是没有递归的比较方法(非常感谢supercat9)
public int Compare(T x, T y) { int index = 0; int count = propertyArray.Length; int result = 0; PropertyInfo propertyInfo; IComparable obj1; IComparable obj2; do { propertyInfo = typeof(T).GetProperty(propertyArray[index]); obj1 = (IComparable)propertyInfo.GetValue(x, null); obj2 = (IComparable)propertyInfo.GetValue(y, null); result = obj1.CompareTo(obj2); if (this.SortingOrder == GenericSortOrder.Descending) { result = -result; } index++; } while (result == 0 && index < count); return result; }
编辑 (2010/08/26) ------------- 修复了一些未转义的 <> 括号。