C# 什么';这是比较器<;T>;上课时间?

C# 什么';这是比较器<;T>;上课时间?,c#,C#,如果指定的类型已经实现了IComparable,那么比较器类有什么用途 如果我指定Comparer.Default,并且Customer已经实现了IComparable,那么为什么我要使用Comparer类?该类型不需要实现IComparable,它可以是任何类型-对t没有任何约束: public abstract class Comparer<T> : IComparer, IComparer<T> 假设您有一个简单的类,Person,并且您想要对Person列表进行

如果指定的类型已经实现了
IComparable
,那么
比较器类有什么用途


如果我指定Comparer.Default,并且Customer已经实现了IComparable,那么为什么我要使用Comparer类?

该类型不需要实现IComparable,它可以是任何类型-
t
没有任何约束:

public abstract class Comparer<T> : IComparer, IComparer<T>
假设您有一个简单的类,
Person
,并且您想要对
Person
列表进行排序,那么您最好编写一个比较器:

public class Person
{
    string Name { get; set; }
}

比较器
保存实际的比较方法。如果您希望将对象与
i可比较
实现中的对象进行不同的比较,则可以使用它。

因为有时您需要将集合/有序队列按“自然”顺序或多个自然顺序进行排序

例如,如果有平面线,则可能需要按以下方式对其进行排序:

  • 航班号
  • 目的地
  • 时间
  • 优先权(某些航班可能比其他航班延误更长时间)
可以通过以下方式计划计算机中的任务:

  • 使用者
  • 优先级(在调度程序中)
  • PID(正常比较)

因此,即使在一个应用程序中,也可能需要按不同的属性对对象进行排序。您不能通过
int compareTo(Object)
方法实现这一点,因为它不能区分上下文。但是,您可以添加上下文,即实现
CompareByPriority

我想您的问题是,为什么一个基类似乎只有一个有用的方法,而这个方法恰好是直接实现接口时要实现的方法。如果我理解正确,我想你是对的,与直接实现
IComparer
相比,从
Comparer
派生没有什么好处,除了基类为你提供了一个泛型和非泛型的实现以及一个重写的方法

但是,如果您的问题是为什么同时拥有
IComparer
IComparable
,那么 正如其他人所指出的,
Comparer
允许您定义执行比较的不同方式。这是一个执行。一个很好的例子是各种
StringComparer
属性,如StringComparer.Ordinal、StringComparer.OrdinalIgnoreCase等。这允许您在
IComparable
接口无法预料的不同情况下对字符串进行不同排序

但除了能够重新定义执行比较的方式外,有时提供外部比较器是唯一的方法。例如,Windows窗体ListView类允许您为其排序逻辑指定IComparer。但是ListViewItem没有实现IComparable。因此,如果没有知道如何进行排序的比较器策略,ListViewItem是不可排序的,因为它没有默认的IComparable实现

因此,归根结底,这只是另一个扩展点,当您不是要排序的类型的作者(或者您需要多种排序策略)时,它允许您具有更大的灵活性


编辑:回应您下面的评论:“如果我有一个实现IComparer的类(我自己的类),这将允许我对任意数量的属性进行排序(自定义排序),那么我为什么还要麻烦使用Comparer.Default?”

也许举个例子会有所帮助。假设您正在编写一个扩展方法,该方法检查给定值是否在一个范围内

public static bool Between<T>(this T value, T minValue, T maxValue) {

    var comparer = Comparer<T>.Default;

    int c1 = comparer.Compare(value, minValue);
    int c2 = comparer.Compare(value, maxValue);

    return (c1 >= 0 && c2 <= 0);

}
public static bool-Between(此T值、T最小值、T最大值){
var comparer=comparer.Default;
int c1=比较器。比较(值,最小值);
int c2=比较器。比较(值,最大值);

return(c1>=0&&c2这里有几个微妙之处:

  • 它不仅支持
    IComparable
    ——它还支持旧的(非泛型)
    IComparable
    作为回退。这意味着它不能仅仅表示为(例如)泛型约束
  • 它支持
    Nullable
    ,其中
    T
    是可比较的,即使
    Nullable
    显然不可
    IComparable
    IComparable
  • 它通过不要求泛型类型约束来防止泛型类型约束的爆炸-例如,
    列表
    可以提供一个
    排序
    ,即使它并不坚持所有的
    t
    都是可排序的;否则泛型约束的累积速度会很快,你会感到惊讶
  • 它允许您将比较器传递到任何需要比较器的现有API中,而您所拥有的只是一个可比较的类型;大多数框架排序API(包括LINQ)都将提供比较器支持
公共级别人员
{
公共字符串LastName;
公共字符串名;
}
公共课2
{
公开无效测试()
{
List classList=新列表();
//向列表中添加一些数据
PersonComparer comp=新的PersonComparer();
classList.Sort(comp);
}
}
公共类人员比较者:比较者
{
公共覆盖整数比较(人员x、人员y)
{
int val=x.LastName.CompareTo(y.LastName);
如果(val==0)
{
val=x.FirstName.CompareTo(y.FirstName);
}
返回val;
}
}

如果一个类型实现了
IComparable
,那么使用它几乎肯定比使用
IComparable
要好。对于值类型,
IComparable
的性能通常比非泛型的
IComparable
好得多。对于可继承的引用类型,
IComparable
可以提供更好的性能通过允许基于派生类型字段的排名,可以实现比
i可比较

对于后一个好处的示例,假设有一个抽象基类
ScheduleEvent
,带有一个属性
public static bool Between<T>(this T value, T minValue, T maxValue) {

    var comparer = Comparer<T>.Default;

    int c1 = comparer.Compare(value, minValue);
    int c2 = comparer.Compare(value, maxValue);

    return (c1 >= 0 && c2 <= 0);

}
public class Person
{
    public string LastName;
    public string FirstName;

}

public class Class2
{
    public void test()
    {
        List<Person> classList = new List<Person>();
        //add some data to the list
        PersonComparer comp = new PersonComparer();
        classList.Sort(comp);
    }
}

public class PersonComparer : Comparer<Person>
{

    public override int Compare(Person x, Person y)
    {
        int val = x.LastName.CompareTo(y.LastName);
        if (val == 0)
        {
            val = x.FirstName.CompareTo(y.FirstName);
        }
        return val;
    }
}