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

如何对泛型列表进行排序?

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.26/5 (11投票s)

2009年8月12日

CPOL

2分钟阅读

viewsIcon

78222

downloadIcon

473

一篇关于如何根据用户定义类的任何属性对泛型列表进行排序的文章

引言

不久前,我被问到一个关于泛型 List<T> 的问题。如何根据用户自定义类的某个数据成员对任何泛型列表进行排序。 我承认我使用 C#.NET 已经 3 年了,但当时我没有直接想到任何方法。 第一个想法是有一个名为 Sort() 的方法。 之后,我尝试通过创建一个示例应用程序来使用它。 有多种方法可以实现它,但在这篇小文章中,我将发布我认为非常简单的解决方案。

背景 

首先,让我们通过一个简单的例子来理解问题。 假设我们有一个组织的员工列表。 现在,为了生成报告,有一些要求需要按姓名或员工 ID 等对该列表进行排序。 因此,我们的问题是如何通过泛型列表实现它,以便只需进行少量更改就可以对任何属性进行排序。

Using the Code

让我们有一个用户定义的 Employee 类。

public class Employee
    {
        #region Private Members

        private Int32 empId;
        private String empName;
        private DateTime empJoiningDate;

        #endregion

        #region Properties

        public Int32 EmployeeId
        {
            get { return empId; }
            set { empId = value; }
        }

        public String EmployeeName
        {
            get { return empName; }
            set { empName = value; }
        }

        public DateTime EmployeeJoiningDate
        {
            get { return empJoiningDate; }
            set { empJoiningDate = value; }
        }

        #endregion
    }

现在,每当我们想要使用排序后的 Employee 列表时,首先我们将创建 List<T>

List<Employee> myEmployeeList = new List<Employee>();

下一步将是使用 Sort() 方法 & 在方法内部编写另一个易于查找的方法 CompareTo()。 但是,这种方法的问题是,有时我们需要指定排序必须基于某些特定属性(即员工的 ID 或姓名)。

public int CompareTo(Employee other)
{
    return EmployeeName.CompareTo(other.EmployeeName);
}

只有当我们确定要进行排序的属性时,上述方法才有用。 否则,最好将要传递的参数用于排序。 为了实现这一点,我们应该使用 IComparable<T>。(点击此处了解详情。)

public class Employee : IComparable<Employee>
{
    [...]
       
    public Int32 CompareTo(Employee other)
    {
        return EmployeeName.CompareTo(other.EmployeeName);
    }            
       
    [...]
}

这里我们有一个固定的属性 Name 用于排序。 为了增加灵活性,我们可以使用委托来避免代码重复。 我们可以为允许进行排序的每个属性声明多个委托。

public class Employee : IComparable<Employee>
{
    [...]
       
    /// <summary>
    /// Comparison of age between the employees.
    /// </summary>
    public static Comparison<Employee> AgeComparison = 
				delegate(Employee p1, Employee p2)
    {
        return p1.empAge.CompareTo(p2.empAge);
    };
        
    /// <summary>
    /// Comparison of name between the employees.
    /// </summary>
    public static Comparison<Employee> NameComparison = 
				delegate(Employee p1, Employee p2)
    {
        return p1.empName.CompareTo(p2.empName);
    };           
       
    [...]
}

通过声明 static 委托,我们可以在将它们作为参数传递给 Sort() 方法时,无需创建 Employee 类的实例即可使用它们。

myEmployeeList.Sort(Employee.NameComparison);
[...]
myEmployeeList.Sort(Employee.AgeComparison);

让我们看一下 Employee 类的完整代码

/// <summary>
/// This class represents the structure, group of this structure is to be sorted.
/// </summary>
public class Employee : IComparable<Employee>
{
    #region Private Members

    private Int32 empId;
    private String empName;
    private UInt32 empAge;

    #endregion
  
    #region Properties
        
    /// <summary>
    /// Gets or sets the employee id / no
    /// </summary>
    public Int32 EmployeeId
    {
        get { return empId; }
        set { empId = value; }
    }

    /// <summary>
    /// Gets or sets the name of the employee
    /// </summary>
    public String EmployeeName
    {
        get { return empName; }
        set { empName = value; }
    }

    /// <summary>
    /// Gets or sets the Age of the employee
    /// </summary>
    public UInt32 EmployeeAge
    {
       get { return empAge; }
       set { empAge = value; }
    }

    #endregion

    #region Constructor
          
    /// <summary>
    /// Creates an instance of an employee class.
    /// </summary>
    /// <param name="id"> Id / no of the employee to be created.</param>
    /// <param name="name">Name of the employee to be created.</param>
    /// <param name="age">Age of the employee to be created.</param>
    public Employee(Int32 id, String name, UInt32 age)
    {
        this.empId = id;
        this.empName = name;
        this.empAge = age;
    }
        
    #endregion

    #region Static Members
    /// <summary>
    /// Comparison of age between the employees.
    /// </summary>
    public static Comparison<Employee> AgeComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empAge.CompareTo(p2.empAge);
    };

    /// <summary>
    /// Comparison of name between the employees.
    /// </summary>
    public static Comparison<Employee> NameComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empName.CompareTo(p2.empName);
    };

    /// <summary>
    /// Comparison of employee Id / No between the employees.
    /// </summary>
    public static Comparison<Employee> IDComparison = delegate(Employee p1, Employee p2)
    {
        return p1.empId.CompareTo(p2.empId);
    };

    #endregion

    #region IComparable<Product> Members
          
    /// <summary>
    /// Compares the current employee object with another object of the same type.
    /// </summary>
    /// <param name="other">An employee object to compare with this object</param>
    /// <returns>A 32-bit signed integer that indicates 
    /// the relative order of the objects being compared.</returns>
    public Int32 CompareTo(Employee other)
    {
        return EmployeeName.CompareTo(other.EmployeeName);
    }

    #endregion

    #region Overridden Methods
           
    /// <summary>
    /// Gets a canonical string representation for the specified employee instance.
    /// </summary>
    /// <returns>A System.String instance that contains the unescaped 
    /// canonical representation of the employee instance</returns>
    public override string ToString()
    {
        return string.Format("Id: {0} Name: {1} Age: {2}", empId, empName, empAge);
    }

    #endregion
}

历史

  • 2009 年 8 月 12 日 -- 提交文章
© . All rights reserved.