65.9K
CodeProject 正在变化。 阅读更多。
Home

适用于集合项目的通用比较类

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.83/5 (11投票s)

2010年3月4日

CPOL

2分钟阅读

viewsIcon

22721

你可能还有更重要的事情要做,而不是编写繁琐的比较方法。

我一直在网上寻找一种方法来排序列表,而无需编写所有自定义的比较方法,并且在c-sharpcorner网站上找到了一篇2006年的代码,作者是一位名叫Dipend Lama的人:    使用泛型排序自定义类型集合
将代码复制到我的项目中并查看结果后,我意识到我偶尔需要一次性按多个属性进行排序。不幸的是,这个类不支持这种设计考虑,所以我不得不自己实现它。我的第一个任务是决定一种传递多个(甚至只有一个)用于搜索的属性的方式。我选择了字符串数组,因为它们在方法调用中很容易实例化。但是,如果只指定了一个属性,我希望允许程序员这样做,而无需创建字符串数组,所以我保留了原始构造函数,并对其进行重载,使其接受一个字符串数组。下一个问题稍微困难一些 - 我该如何使用所有属性来排序列表?我的解决方案归结为一种基本的编程实践 - 递归。说实话,递归并不常见。在过去的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) ------------- 修复了一些未转义的 <> 括号。
© . All rights reserved.