【问题标题】:When to use IComparable<T> Vs. IComparer<T>何时使用 IComparable<T>比较器<T>
【发布时间】:2009-02-11 18:20:08
【问题描述】:

我正在尝试找出我需要实现哪些接口。他们基本上都做同样的事情。我什么时候会使用其中一个?

【问题讨论】:

标签: .net icomparable icomparer


【解决方案1】:

它们并不完全IComparer&lt;T&gt; 是在能够比较两个不同对象的类型上实现的,而IComparable&lt;T&gt; 是在能够比较自身的类型上实现的其他同类型的实例。

当我需要知道另一个实例与this 实例的关系时,我倾向于使用IComparable&lt;T&gt;IComparer&lt;T&gt; 可用于对集合进行排序,因为 IComparer&lt;T&gt; 位于比较之外。

【讨论】:

  • IComparer 还允许您为所需的每种排序类型设置一个类。例子; PersonLastFirstNameComparer、PersonFirstLastNameComparer 或 PersonAgeComparer。
  • 您有没有一种简单的方法来记住它们?我倾向于每次都查一下。
  • @amadib 认为IComparable 我是可比的​​>。这意味着我可以与其他东西进行比较。并把IComparer读作我是一个比较者,我只是比较,这意味着我比较了一些东西。
  • @newfal 你应该把这个作为答案。我认为这是最好的解释。
【解决方案2】:

当类具有内在比较时,使用IComparable&lt;T&gt;

如果您需要类的内在比较以外的比较方法(如果有的话),请使用 IComparer&lt;T&gt;

【讨论】:

    【解决方案3】:

    这取决于实体。例如,对于像“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;
        }
    }
    

    【讨论】:

    • 将比较方法设为静态以便于使用。
    【解决方案4】:

    通过故事进行简单解释

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

    IComparer 界面 - 比较两个不同的人

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

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

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

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

    比较器类呢?

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

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

    总结

    • IComparer - 排列两个东西并进行比较。
    • IComparable - 在 FB 上与他人进行比较。

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

    【讨论】:

    • 我喜欢你阐释关键概念的方式。如果您将 Comparer(T) 类包含在本次比赛中可能会更好。即使它不包括在问题中。 :)
    【解决方案5】:

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

    引用 this blog post 的 Dave G:

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

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

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

    简而言之: 对值类型使用 IComparable,对引用类型使用 IComparer。

    【讨论】:

      【解决方案6】:

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

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

      【讨论】:

      • -1:返回布尔值不等同于 IComparer。 IComparer 返回一个可以小于零/零/大于零的值,通常用于排序。
      • 当你需要的时候,你会返回一个 int (或者更好的是,一个 enum )。这真的很重要吗?
      • 您甚至可以返回一个布尔值,因为小于是排序序列所需的唯一操作。
      • 一个IComparer实现只需要定义一次,如果需要在更多的地方使用排序逻辑,那么lambda表达式将需要编写更多次。
      • oɔɯǝɹ - 然后您可以存储对委托的引用,该引用被编写为 lambda 表达式并重用它。
      【解决方案7】:

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

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

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

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

      使用 Array 类对 Array 进行排序 2. 需要使用 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 { 公共 int 比较(员工 x,员工 y) { 如果 (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

      【讨论】:

        【解决方案8】:

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

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-01-29
          • 1970-01-01
          • 2017-02-24
          • 1970-01-01
          • 1970-01-01
          • 2013-11-20
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多