构建可比较的对象(IComparable)

IComparable接口

  System.IComparable接口指定了一种允许一个对象可基于某些特定键值进行排序的行为。

namespace System
{
    [ComVisible(true)]
    public interface IComparable
    {
        int CompareTo(object obj);
    }
}

CompareTo()方法背后的逻辑是,根据某个特定数据字段比较传入的对象与当前实例。CompareTo()方法的返回值被用来判断这个类型小于、大于或是等于它所比较的对象。

  • 任何小于0的数字:这个实例在指定对象之前
  • 0:这个实例等于指定对象
  • 任何大于0的数字:这个实例在指定对象之后

构建可比较对象

  System.Array类定义了一个名为 Sort()的静态方法。在内置类型(int、short、string等)上调用这个方法的时候,可以以数字/字母顺序对数组中的项排序,因为这些内置数据类型实现了IComparable。

构建可排序的Car类型

namespace ComparableCar
{
    class Car : IComparable
    {
        public int CurrentSpeed { get; set; }
        public string PetName { get; set; }
        public int CarID { get; set; }
public Car() { } public Car( string name, int currSp, int id ) { CurrentSpeed = currSp; PetName = name; CarID = id; }

int IComparable.CompareTo(object obj) { Car temp = obj as Car; if (temp != null) { if (this.CarID > temp.CarID) return 1; if (this.CarID < temp.CarID) return -1; else return 0; } else throw new ArgumentException("Parameter is not a Car!"); } } }

  由于C#int数据类型(只是CLR System.Int32的简写形式)实现了IComparable,我们就可以按如下所示的方法实现ICompareTo()方法:

        int IComparable.CompareTo( object obj )
        {
            Car temp = obj as Car;
            if (temp != null)
                return this.CarID.CompareTo(temp.CarID);
            else
                throw new ArgumentException("Parameter is not a Car!");
        }

  Car类型已经知道如何将它自己和类似对象进行对比:

namespace ComparableCar
{
    class Program
    {
        static void Main( string[] args )
        {
            Console.WriteLine("***** Fun with Object Sorting *****
");
Car[] myAutos = new Car[5]; myAutos[0] = new Car("Rusty", 80, 1); myAutos[1] = new Car("Mary", 40, 234); myAutos[2] = new Car("Viper", 40, 34); myAutos[3] = new Car("Mel", 40, 4); myAutos[4] = new Car("Chucky", 40, 5); Console.WriteLine("Here is the unordered set of cars:"); foreach (Car c in myAutos) Console.WriteLine("{0} {1}", c.CarID, c.PetName); Array.Sort(myAutos); Console.WriteLine(); Console.WriteLine("Here is the ordered set of cars:"); foreach (Car c in myAutos) Console.WriteLine("{0} {1}", c.CarID, c.PetName); Console.ReadLine(); } } }

指定多个排序顺序IComparer

  如果要构建一个既可通过ID排序又可通过昵称排序的Car类型,就需要与另一个标准接口IComparer打交道。

namespace System.Collections
{
    [ComVisible(true)]
    public interface IComparer
    {
        int Compare(object x, object y);
    }
}

   与IComparable接口不同,IComparer接口不是在要排序的类型(即Car)中,而是在许多辅助类中实现的,其中每个排序各有一个依据(如昵称、ID号等)。

namespace ComparableCar
{
    //  这个辅助类用来通过昵称排序Car类型的数组
    public class PetNameComparer : IComparer
    {
        // 测试每个对象的昵称
        int IComparer.Compare( object o1, object o2 )
        {
            Car t1 = o1 as Car;
            Car t2 = o2 as Car;
            if (t1 != null && t2 != null)
                return String.Compare(t1.PetName, t2.PetName);
            else
                throw new ArgumentException("Parameter is not a Car!");
        }
    }
}

   System.Array有许多重载的Sort()方法,其中有一个用来在对象上实现IComparer接口。

namespace ComparableCar
{
    class Program
    {
        static void Main( string[] args )
        {
            ...
            // 按照昵称进行排序
            Array.Sort(myAutos, new PetNameComparer());

            Console.WriteLine("Ordering by pet name:");
            foreach (Car c in myAutos)
                Console.WriteLine("{0} {1}", c.CarID, c.PetName);
            ...
        }
    }
}

自定义属性、自定义排序类型

   值得指出的是,在通过特定数据字段排序Car类型的时候,可以使用自定义的静态属性辅助对象用户。假定Car类型添加了一个静态只读属性SortByPetName,它返回一个实现了IComparer接口的对象的实例(在本例中为PetNameComparer):

namespace ComparableCar
{
// 现在可以使用一个自定义静态属性来返回正确的IComparer接口
class Car : IComparable {
... // 返回SortByPetName比较的属性 public static IComparer SortByPetName { get { return (IComparer)new PetNameComparer(); } }
     ...
} }

   现在可以使用强关联属性按照昵称排序,而不是只能使用独立的PetNameComparer类型:

// 简洁明了的按照昵称排序
Array.Sort(myAutos, Car.SortByPetName);
原文地址:https://www.cnblogs.com/gyt-xtt/p/6266043.html