C#学习笔记(二十五)-- IComparable和IComparer接口

发布时间:2023-03-12 11:00

  IComparable和IComparer接口是.NET Framework中比较对象的标准方式。这两个接口之间的区别如下:

  IComparable在要比较的对象的类中实现,可以比较该对象和另一个对象。

  IComparer在一个单独的类中实现,可以比较任意两个对象。

  一般使用IComparable给出类的默认比较带啊,使用其他类给出非默认的比较代码。

  IComparable提供了一个方法CompareTo(),这个方法接受一个对象。例如,在实现该方法时,使其可以接受一个Person对象,以便确定这个人比当前的人更年老还是更年轻。实际上,这个方法返回一个int,所以也可以确定第二个人与当前的人的年龄差:

if(person1.Compareto(person2) == 0)
{
   WriteLine("Same age");
}
else if(person1.CompareTo(person2) > 0)
{
   WriteLine("Person 1 is older");

}
else
{
   WriteLine("Person 2 is older");
}

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

if(personComparer.Compare(person1, person2) == 0)
{
   WriteLine("Same age");
}
else if(personComparer.Compare(person1, person2) > 0)
{
   WriteLine("Person 1 is older");
}
else
{
   WriteLine("Person 2 is older");
}

  这两种情况下,提供给方法的参数是System.Object类型。这意味者可以比较一个对象与其他任意类型的另一个对象。所以,在返回结果之前,通常需要进行某种类型比较,如果使用了错误类型,还会抛出异常。

  .NET Framework在类Comparer上提供了IComparer接口的默认实现代码,类Compare位于System.Collections的名称空间中,可以对简单类型以及支持IComparable接口的任意类型进行特定文化的比较。例如,可通过下面的代码使用它:

string firstString = "First String";
string secondString = "Second String";
WriteLine($"Comparing '{firstString}' and '{secondString}',"+$"result:{Comparer.Default.Compare(firstString, secondString)}");
int firstNumber = 35;
int secondNumber = 23;
WriteLine($"Comparing '{firstNumber}' and '{secondNumber}',"+$"result:{Comparer.Default.Compare(firstNumber, secondNumber)}");

  这里使用Compare.Default静态成员获取Comparer类的一个实例,接着使用Compare()方法比较前两个字符串,之后比较两个整数,结果如下:

Comparing 'First String' and 'Second String', result: -1
Comparing '35' and '23',result: 1

  在字母表中,F在S的前面,所以F“小于”S,第一个比较的结果就是-1。同样,35大于23,所以结果是1。注意这里的结果并未给出相差的幅度。

  在使用Comparer时,必须使用可以比较的类型。例如,试图比较firstString和firstNumber就会生成一个异常。

  下面列出了有关这个类的一些注意事项:

  1)检查传递给Comparer.Compare()的对象,看看它们是否支持IComparable。如果支持,就使用该实现代码。

  2)允许使用null值,它被解释为“小于”其他的任意对象。

  3)字符串根据当前文化来处理。要根据不同的文化(或语言)处理字符串,Comparer类必须使用其构造函数进行实例化,以便传送与指定所使用的文化的System.Globalization.CultureInfo对象。

  4)字符串在处理时要区分大小写。如果要以不区分大小写的方式来处理它们,就需要使用CaseInsensitiveComparer类,该类以相同的方式工作。

  许多集合类可以用对象的默认方式进行排序,或者用定制方法来排序。ArrayList就是一个实例,它包含方法Sort(),这个方法使用时可以不带参数,此时使用默认的比较方式,也可以给他传递IComparer接口,以比较对象对。

  给ArrayList填充了简单类型时,例如整数或字符串,就会进行默认的比较。对于自己的类,必须在类定义中实现IComparable,或创建一个支持IComparer的类,来进行比较。

  注意,System.Collections名称空间中的一些类(包括CollectionBase)都没有提供排序方法。如果要对派生于这个类的集合排序,就必须多做一些工作,自己给内部的List集合排序。

  添加一个新类Person:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ch11Ex05
{
    class Person : IComparable
    {
        public string Name;
        public int Age;
        public Person(string name, int age)
        {
            Name = name;
            Age = age;
        }
        public int CompareTo(object obj)
        {
            if (obj is Person)
            {
                Person otherPerson = obj as Person;
                return this.Age - otherPerson.Age;
            }
            else
            {
                throw new ArgumentException(
                   "Object to compare to is not a Person object.");
            }
        }
    }
}

  添加一个新类PersonCompareName:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ch11Ex05
{
    public class PersonComparerName : IComparer
    {
        public static IComparer Default = new PersonComparerName();
        public int Compare(object x, object y)
        {
            if (x is Person && y is Person)
            {
                return Comparer.Default.Compare(
                   ((Person)x).Name, ((Person)y).Name);
            }
            else
            {
                throw new ArgumentException(
                   "One or both objects to compare are not Person objects.");
            }
        }
    }
}

  修改Program.cs中的代码如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using static System.Console;

namespace Ch11Ex05
{
    class Program
    {
        static void Main(string[] args)
        {
            ArrayList list = new ArrayList();
            list.Add(new Person("Rual", 30));
            list.Add(new Person("Donna", 25));
            list.Add(new Person("Mary", 27));
            list.Add(new Person("Ben", 44));
            WriteLine("Unsorted people:");
            for (int i = 0; i < list.Count; i++)
            {
                WriteLine($"{(list[i] as Person).Name } ({(list[i] as Person).Age })");
            }
            WriteLine();
            WriteLine(
               "People sorted with default comparer (by age):");
            list.Sort();
            for (int i = 0; i < list.Count; i++)
            {
                WriteLine($"{(list[i] as Person).Name } ({(list[i] as Person).Age })");
            }
            WriteLine();
            WriteLine(
               "People sorted with nondefault comparer (by name):");
            list.Sort(PersonComparerName.Default);
            for (int i = 0; i < list.Count; i++)
            {
                WriteLine($"{(list[i] as Person).Name } ({(list[i] as Person).Age })");
            }
            ReadKey();
        }
    }
}

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号