代码改变世界

Effective C# 学习笔记(三十一)利用IComparable<T>和IComparer<T>接口来实现排序关系

2011-07-17 21:13  小郝(Kaibo Hao)  阅读(381)  评论(0编辑  收藏  举报

你的类型需通过描述在集合中该类型的对象该如何排序和被查找来说明其排序关系。

.NET framework中定义了IComaprable<T>IComparer<T>接口来为你的类型定义排序关系。

前者定义了你类型的自然排序方式,后者则定义了其他的排序方式(通过<,>,<=,>=等运算关系的定义来提高在运行时的比较性能)。

IComparable<T>接口包含一个CompareTo()方法(该方法的时间复杂度平均为n lg(n)),该方法返回0时该对象和比较对象相等,返回小于0的值时则该对象小于比较对象,返回大于0值时该对象大于比较对象。而为了和一些旧的APIs相兼容,你需要同时实现IComparable非范型比较接口,该接口的CompareTo接受Object对象类型参数,所以你要对类型进行转换检查。下面的代码是一个简单的实现:

 

public struct Customer : IComparable<Customer>, IComparable

{

private readonly string name;

 

public Customer(string name)

{

this.name = name;

}

#region IComparable<Customer> Members

public int CompareTo(Customer other)

{

return name.CompareTo(other.name);

}

#endregion

#region IComparable Members

int IComparable.CompareTo(object obj)

{

if (!(obj is Customer))

throw new ArgumentException(

"Argument is not a Customer", "obj");

Customer otherCustomer = (Customer)obj;

return this.CompareTo(otherCustomer);

}

#endregion

}

 

出了实现Icomparable<T>IComparable接口外,你还可以定义比较运算符来给客户端提供更方便的比较方式,代码如下:

public struct Customer : IComparable<Customer>, IComparable

{

private readonly string name;

public Customer(string name)

{

this.name = name;

}

#region IComparable<Customer> Members

public int CompareTo(Customer other)

{

return name.CompareTo(other.name);

}

#endregion

#region IComparable Members

int IComparable.CompareTo(object obj)

{

if (!(obj is Customer))

throw new ArgumentException(

"Argument is not a Customer", "obj");

Customer otherCustomer = (Customer)obj;

return this.CompareTo(otherCustomer);

}

#endregion

// Relational Operators.

public static bool operator <(Customer left,Customer right)

{

return left.CompareTo(right) < 0;

}

public static bool operator <=(Customer left,Customer right)

{

return left.CompareTo(right) <= 0;

}

public static bool operator >(Customer left,Customer right)

{

return left.CompareTo(right) > 0;

}

public static bool operator >=(Customer left,Customer right)

{

return left.CompareTo(right) >= 0;

}

}

 

通过创建静态属性来提供非标准的排序支持定义,代码如下:

public static Comparison<Customer> CompareByReview

{

get

{

return (left,right) => left.revenue.CompareTo(right.revenue);

}

}

 

而一些旧的类库需要通过实现IComparer接口的功能,来提供非标准的排序定义。注意:这种通过创建辅助排序类来定义排序的方式建议只在你没有权限访问到原有类型的源码时使用。代码如下:

 

//1. 先定义一个继承自IComparer<T>接口的类型:

// Class to compare customers by revenue.

// This is always used via the interface pointer,

// so only provide the interface override.

private class RevenueComparer : IComparer<Customer>

{

#region IComparer<Customer> Members

int IComparer<Customer>.Compare(Customer left,Customer right)

{

return left.revenue.CompareTo(

right.revenue);

}

#endregion

}

 

//2. 定义该类型的静态属性,单例形式创建

private static RevenueComparer revComp = null;

 

// return an object that implements IComparer

// use lazy evaluation to create just one.

public static IComparer<Customer> RevenueCompare

{

get

{

if (revComp == null)

revComp = new RevenueComparer();

return revComp;

}

}