c# 实现IComparable、IComparer接口、Comparer类的详解

IComparable和ICompare 接口是.net framework 中比较对象的标准方式,这两个接口之间的区别如下:
1. IComparable 在要比较的对象的类中实现,可以比较该对象和另一个对象。
2.IComparer 在一个单独的类中实现,可以比较任意两个对象。
一般情况下,我们使用 IComparable 给出类的默认比较代码,使用其他类给出非默认的比较代码。
一、IComparable提供了一个方法int CompareTo(object obj)。这个方法接受一个对象,所以可以实现这个接口
比如:以便把 Person 对象传送给它,
说明这个人是否比当前的人更年老或年轻。实际上,这个方法返回一个int,所以可和下面的代码说明第二个人更年老还是更年轻。

代码如下:


if(person1.CompareTo(person2) == 0)
{
  Console.WriteLine("Sameage");
}
else if(person1.CompareTo(person2) > 0 )
{
  Console.WriteLine("person1 is older");
}
else
{
  Console.WriteLine("person1is younger");
}


二、IComparer 也提供了一个方法Compare().这个方法接受两个对象,返回一个整型结果,这与 CompareTo()相同。
对于支持 IComparer的对象,可以使用下面的代码:

代码如下:


if(personComparer.Compare(person1,person2) == 0)
{
  Console.WriteLine("sameage");
}
else if(personComparer.Compare(person1,person2) > 0 )
{
  Console.WriteLine("person1 is older");
}
else
{
  Console.WriteLine("person1is younger");
}


在这两种情况下,提供给方法的参数是system.object类型。也就是说,可以比较任意类型的两个对象。所以,在返回结果之前,通常需要进行某种类型比较,如果使用了错误的类型,还会抛出异常。实际上,我们是使用泛型接口IComparable<T>,可以省略对象转换。可以参见后面的日记。
三、.net framework 在类 Comparer 上提供了IComparer 接口的默认实现方式,类 Comparer 位于system.collections 名称空间中,可以对简单类型以及支持IComparable
接口的任意类型进行特定文化的比较。
例如,可以通过下面的代码使用它:

代码如下:


string firststring = "First String";
string secondstring = "Second string";
Comparer.Default.Compare(firststring , secondstring);

int firstNumber = 35;
int secondNumber = 23;
Comparer.Default.Compare(firstNumber , secondNumber);


这里使用Comparer.Default静态成员获取Comparer类的一个实例,接着使用 Compare()方法来比较。
在使用 Comparer时,必须使用可以比较的类型。例如,试图比较firstString 和 firstNumber 就会生成一个异常。
下面是这个类的一些注意事项:

.net框架包含两个类,实现了IComparer接口,ComparerCaseInsensitiveComparer类提供了IComparer的基本实现方式。
1
)不要使用new运算符直接创建Comparer类的实例,应调用Default方法,该方法将返回一个已被适当地初始化过的Comparer对象,如下:
ComparertheComparer=Comparer.Default

拥有Comparer对象以后,可以将比较类委托给调用它的Compare方法,如下:
publicint Compare
(object x,object y)
{

  returnComparer.Default.Compare(x,y);
}

2)CaseInsensitiveComparer类的行为与Comparer类非常相似,都是通过ICompareble接口比较任意两个对象,区别是前者对遇到的字符串不区分大小写的比较。与Comparer类似,初始化过的CaseInsensitiveComparer对象可以使用静态Default方法来获取索引,如下:
CaseInsensitiveCompareraComparer=CaseInsensitiveComparer.Default

### C# 中 `List<T>.Sort` 方法详解 #### 排序基础 在C#中,`List<T>` 提供了一个名为 `Sort()` 的方法来对列表中的元素进行排序。对于基本数据型的列表,默认情况下会按照升序排列[^1]。 ```csharp // 创建并初始化整数列表 var numbers = new List<int> { 2, 1, 3, 4, 5 }; numbers.Sort(); foreach (var num in numbers) { Console.Write(num + " "); } Console.WriteLine(); // 输出:1 2 3 4 5 ``` 为了实现降序排序,在比较器内部可以简单地交换两个操作数的位置或给返回的结果加上负号: ```csharp // 对于整数列表执行降序排序 numbers.Sort((x, y) => -(x.CompareTo(y))); foreach (var num in numbers) { Console.Write(num + " "); } Console.WriteLine(); // 输出:5 4 3 2 1 ``` #### 自定义型排序 当处理复杂的数据结构如实例时,则需要提供额外的信息告诉程序如何对比这些对象之间的顺序。这可以通过几种方式完成: - **通过实现 `IComparable<T>` 或者 `IComparer<T>` 接口** 如果希望某个特定型的集合总是遵循某种固定的排序逻辑,可以在该型本身内嵌入这种行为——即让这个型继承自 `IComparable<T>` 并重写其成员函数 `CompareTo(T other)` 来指定具体的比较规则;或者创建一个新的实现了 `IComparer<T>` 的作为外部比较器传递给 `Sort()` 函数调用。 - **利用匿名委托表达式** 当只需要临时改变一次性的排序策略而不必修改原有代码库的时候,可以选择直接在线编写简单的 lambda 表达式来进行快速定制化排序。这种方式特别适合那些只涉及几个字段的情况。 下面是一个例子展示了如何基于键值对内的属性对 `KeyValuePair` 型的对象数组做排序: ```csharp public class KeyValuePair { public uint id; public string s = ""; public float d; public double c; // 构造函数省略... } // 假设有这样一个包含多个键值对的列表 var kvps = new List<KeyValuePair>(); kvps.Add(new KeyValuePair { id = 1U, s = "apple", d = 0.5F }); kvps.Add(new KeyValuePair { id = 2U, s = "banana", d = 0.7F }); // 按照字符串 's' 成员降序排列 kvps.Sort((a, b) => -String.Compare(a.s, b.s)); foreach (var kvp in kvps) { Console.WriteLine($"{kvp.id}: {kvp.s}"); } ``` 上述代码片段将会先打印 `"banana"` 后跟 `"apple"` ,因为字母表上 B 大于 A 所以 banana 应位于 apple 之前。 另外还有一种更灵活的方式是使用 LINQ 查询语法配合 OrderBy / ThenBy 系列扩展方法来做多级条件下的排序组合,不过这里不再赘述。 #### 参数化的部分排序 有时候可能并不想整个序列都被重新安排而是只想调整其中一部分子集里的相对位置关系。这时就可以借助带有三个参数版本的 `Sort(int index, int count, IComparer comparer)` 进行局部范围的操作了[^2]: ```csharp // 只针对前半段元素按浮点数'd'从小到大排序 int halfSize = kvps.Count / 2; kvps.Sort(0, halfSize, Comparer<float>.Create((left, right) => left.CompareTo(right))); for (int i = 0; i < kvps.Count; ++i) { var item = kvps[i]; Console.WriteLine($"Index={i}, Value={item.d}"); } ``` 这段代码仅影响到了列表开头至中间位置处各元素间的先后次序而不会干扰其余部分的内容布局。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值