IComparable接口
System.IComparable接口指定了一种允许一个对象可基于某些特定键值进行排序的行为。
namespaceSystem
{
[ComVisible(true)]public interfaceIComparable
{
int CompareTo(objectobj);
}
}
CompareTo()方法背后的逻辑是,根据某个特定数据字段比较传入的对象与当前实例。CompareTo()方法的返回值被用来判断这个类型小于、大于或是等于它所比较的对象。
任何小于0的数字:这个实例在指定对象之前
0:这个实例等于指定对象
任何大于0的数字:这个实例在指定对象之后
构建可比较对象
System.Array类定义了一个名为 Sort()的静态方法。在内置类型(int、short、string等)上调用这个方法的时候,可以以数字/字母顺序对数组中的项排序,因为这些内置数据类型实现了IComparable。
构建可排序的Car类型
namespaceComparableCar
{classCar : IComparable
{
public int CurrentSpeed { get; set; }public string PetName { get; set; }public int CarID { get; set; }
publicCar() { }public Car( string name, int currSp, intid )
{
CurrentSpeed=currSp;
PetName=name;
CarID=id;
}int IComparable.CompareTo(objectobj)
{
Car temp= obj asCar;if (temp != null)
{if (this.CarID >temp.CarID)return 1;if (this.CarID
return 0;
}else
throw new ArgumentException("Parameter is not a Car!");
}}}
由于C#int数据类型(只是CLR System.Int32的简写形式)实现了IComparable,我们就可以按如下所示的方法实现ICompareTo()方法:
int IComparable.CompareTo( objectobj )
{
Car temp= obj asCar;if (temp != null)return this.CarID.CompareTo(temp.CarID);else
throw new ArgumentException("Parameter is not a Car!");
}
Car类型已经知道如何将它自己和类似对象进行对比:
namespaceComparableCar
{classProgram
{static void Main( string[] args )
{
Console.WriteLine("***** Fun with Object Sorting *****\n");
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 inmyAutos)
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 inmyAutos)
Console.WriteLine("{0} {1}", c.CarID, c.PetName);Console.ReadLine();
}
}
}
指定多个排序顺序IComparer
如果要构建一个既可通过ID排序又可通过昵称排序的Car类型,就需要与另一个标准接口IComparer打交道。
namespaceSystem.Collections
{
[ComVisible(true)]public interfaceIComparer
{
int Compare(object x, objecty);
}
}
与IComparable接口不同,IComparer接口不是在要排序的类型(即Car)中,而是在许多辅助类中实现的,其中每个排序各有一个依据(如昵称、ID号等)。
namespaceComparableCar
{//这个辅助类用来通过昵称排序Car类型的数组
public classPetNameComparer : IComparer
{//测试每个对象的昵称
int IComparer.Compare( object o1, objecto2 )
{
Car t1= o1 asCar;
Car t2= o2 asCar;if (t1 != null && t2 != null)returnString.Compare(t1.PetName, t2.PetName);else
throw new ArgumentException("Parameter is not a Car!");
}
}
}
System.Array有许多重载的Sort()方法,其中有一个用来在对象上实现IComparer接口。
namespaceComparableCar
{classProgram
{static void Main( string[] args )
{
...
//按照昵称进行排序
Array.Sort(myAutos, newPetNameComparer());Console.WriteLine("Ordering by pet name:");foreach (Car c inmyAutos)
Console.WriteLine("{0} {1}", c.CarID, c.PetName);
...
}
}
}
自定义属性、自定义排序类型
值得指出的是,在通过特定数据字段排序Car类型的时候,可以使用自定义的静态属性辅助对象用户。假定Car类型添加了一个静态只读属性SortByPetName,它返回一个实现了IComparer接口的对象的实例(在本例中为PetNameComparer):
namespaceComparableCar
{
// 现在可以使用一个自定义静态属性来返回正确的IComparer接口classCar : IComparable
{...//返回SortByPetName比较的属性
public staticIComparer SortByPetName
{get { return (IComparer)newPetNameComparer(); } }
...}}
现在可以使用强关联属性按照昵称排序,而不是只能使用独立的PetNameComparer类型:
//简洁明了的按照昵称排序
Array.Sort(myAutos, Car.SortByPetName);