104

我试图弄清楚我需要实现哪些接口。他们基本上都做同样的事情。我什么时候会使用其中一个?

4

8 回答 8

99

好吧,它们与在能够比较两个不同对象的类型上实现而在能够与同一类型的其他实例进行比较的类型上实现并不完全相同IComparer<T>IComparable<T>

IComparable<T>当我需要知道另一个实例如何与实例相关时,我倾向于使用它this。 作为比较之外的立场,IComparer<T>对于对集合进行排序很有用。IComparer<T>

于 2009-02-11T18:27:30.043 回答
43

IComparable<T>当类具有内在比较时使用。

IComparer<T>当您需要一种比较方法而不是类的内在比较(如果有的话)时使用。

于 2009-02-11T18:24:31.473 回答
29

这取决于实体。例如,对于像“Student”这样的类,使用基于 Name 的 IComparable 是有意义的。

class Student : IComparable 
{
    public string Name { get; set; }
    public int MathScore { get; set; }
    public int EnglishScore { get; set; }

    public int TotalScore 
    {
        get
        {
            return this.MathScore + this.EnglishScore; 
        }
    }

    public int CompareTo(object obj)
    {
        return CompareTo(obj as Student);  
    }

    public int CompareTo(Student other)
    {
        if (other == null)
        {
            return 1;
        }
        return this.Name.CompareTo(other.Name);  
    }
}

但是,如果老师“A”想根据 MathScore 比较学生,而老师“B”想根据 EnglishScore 比较学生。单独实现 IComparer 是个好主意。(更像是一种策略模式)

class CompareByMathScore : IComparer<Student>
{
    public int Compare(Student x, Student y)
    {
        if (x.MathScore > y.MathScore)
          return 1;
        if (x.MathScore < y.MathScore)
          return -1;
        else
          return 0;
    }
}
于 2011-03-15T07:22:51.023 回答
10

这完全取决于您的类型是否可变。您应该在非可变类型上实现 IComparable。请注意,如果您实现 IComparable,则必须重写 Equals 以及 ==、!=、< 和 > 运算符(请参阅代码分析警告 CA1036)。

引用此博客文章中的 Dave G :

但正确的答案是如果您的对象是可变的,则实现 IComparer 而不是 IComparable,并在必要时将 IComparer 的实例传递给排序函数。

由于 IComparer 只是用于在该时间点进行排序的一次性对象,因此您的对象可以具有您想要的任何可变语义。此外,它不需要甚至不建议使用 Equals、GetHashCode 或 == - 您可以随意以任何方式定义它。

最后,您可以为您的类型定义多个 IComparer,以便按不同的字段或使用不同的规则进行排序。这比坚持一个定义要灵活得多。

简而言之: 将 IComparable 用于值类型,将 IComparer 用于引用类型。

于 2010-10-17T23:11:10.093 回答
10

通过故事简单解释

高中篮球。这是球队的校园选秀权。我想让我的团队中最高/最好/最快的人。我该怎么办?

IComparer Interface - 比较两个不同的人

  • 这让我可以比较任何两个排队的人............基本上就是这样。Fred vs John........我把它们扔到一个实现接口的具体类中。Compare(Fred, John)它吐出谁更好。

IComparable 怎么样?- 将自己与他人进行比较

你最近上FB了吗?您会看到其他人在做很酷的事情:环游世界,创造发明,而我正在做一些不那么酷的事情——我们正在做的是利用 IComparable 接口。

  • 我们将当前实例(您自己)与另一个具有相同类型(人)的对象(其他人)进行比较。

比较器类呢?

Comparer 类是实现 IComparer 接口的抽象基类。您应该从此类派生以获得具体的实现。无论如何,Microsoft 建议您使用 Comparer 类而不是实现 IComparer 接口:

我们建议您从 Comparer 类派生而不是实现 IComparer 接口,因为 Comparer 类提供了 IComparer.Compare 方法的显式接口实现以及获取对象的默认比较器的 Default 属性。

概括

  • IComparer - 排列两件事并进行比较。
  • IComparable - 在 FB 上与他人进行比较。

希望这些故事能帮助你记住。

于 2016-02-05T01:20:28.457 回答
4

正如其他人所说,他们不做同样的事情。

无论如何,这些天我倾向于不使用 IComparer。我为什么要?它的职责(用于比较两个对象的外部实体)可以用 lambda 表达式处理得更干净,类似于大多数 LINQ 方法的工作方式。编写一个快速 lambda,它将要比较的对象作为参数,并返回一个布尔值。如果对象定义了自己的内在比较操作,它可以实现 IComparable 代替。

于 2009-02-11T19:34:42.113 回答
4

IComparer 是一个用于对 Array 进行排序的接口,该接口将强制类实现 Compare(T x,T y) 方法,该方法将比较两个对象。实现该接口的类的实例用于数组的排序。

IComparable 是在需要比较相同类型的两个对象的类型中实现的接口,这个可比较的接口将强制类实现以下方法 CompareTo(T obj)

IEqualityComparer 是一个用于查找对象是否相等的接口,现在我们将在示例中看到这一点,我们必须在集合中查找对象的 Distinct。这个接口将实现一个方法 Equals(T obj1,T obj2)

现在我们举一个例子,我们有一个 Employee 类,基于这个类我们必须创建一个 Collection。现在我们有以下要求。

使用 Array 类 2 对 Array 进行排序。需要使用 Linq 的集合:删除重复项,按从高到低排序,删除一个员工 ID

abstract public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
    public string Address { set; get; }
}

public enum SortType
{
    ByID,
    BySalary
}

公共类 EmployeeIdSorter : IComparer { public int Compare(Employee x, Employee y) { if (x.Id < y.Id) return 1; 否则如果 (x.Id > y.Id) 返回 -1;否则返回 0;} }

    public class EmployeeSalarySorter : IComparer<Employee>
    {
        public int Compare(Employee x, Employee y)
        {
            if (x.Salary < y.Salary)
                return 1;
            else if (x.Salary > y.Salary)
                return -1;
            else
                return 0;
        }
    }

有关更多信息,请参阅以下 http://dotnetvisio.blogspot.in/2015/12/usage-of-icomparer-icomparable-and.html

于 2016-09-09T03:49:43.553 回答
3

IComparable 表示一个对象可以与另一个对象进行比较。IComparer 是一个可以比较任意两个项目的对象。

于 2009-02-11T18:28:26.127 回答