为什么在单独的类中实现IEqualityComparer <t>

时间:2016-02-10 11:51:23

标签: c# linq compare

当我在msdn上查找通用IEqualityComparer接口时,我注意到接口是在一个单独的'comparer'类中实现的,而不是在类本身中实现的IEquatable<T> 。当我搜索更多的例子时,每一个都使用了一个单独的类,让我想知道:为什么不在类本身上实现它?

我可以想象覆盖object.Equalsobject.GetHashCode不被认为是好习惯,因为它用于很多不同的情况,但即使msdn说(强调我的):

  

此界面允许实施集合的自定义相等比较。

因此它的用途几乎仅限于Linq。我可以想到为什么要定义一个单独的比较器类只有两个原因:

  1. 对类集合的不同方法需要不同的比较器。
  2. 这个类很大,并且实例化它的另一个对象是不可取的(尽管如果这真的是问题,为什么没有整个集合它不坏?)。
  3. 所以我的问题是:

    有什么特别的原因让我忽略了导致每个人定义另一个comparerclass只是为了比较而不是仅仅在类本身上实现接口(在我看来,至少可以说这不会更糟)?

    一个小例子:

    public static void Main(string[] args)
    {
        Test t1 = new Test { id = 1, date = default(DateTime) };
        Test t2 = new Test { id = 1, date = default(DateTime) };
        Test t3 = new Test { id = 0, date = default(DateTime) };
        List<Test> testList = new List<Test>{ t1, t2, t3 };
    
        //Same result
        int distinctCountClass = testList.Distinct(new Test()).Count();
        int distinctCountComparerClass = testList.Distinct(new TestComparer()).Count();
    }
    
    public partial class Test
    {
        public int id { get; set; }
        public DateTime date { get; set; }
    }
    
    public partial class Test : IEqualityComparer<Test>
    {
        public bool Equals(Test x, Test y) { return x.id == y.id && x.date == y.date; }
        public int GetHashCode(Test obj) { return obj.id.GetHashCode(); }
    }
    
    public class TestComparer : IEqualityComparer<Test>
    {
        public bool Equals(Test x, Test y) { return x.id == y.id && x.date == y.date; }
        public int GetHashCode(Test obj) { return obj.id.GetHashCode(); }
    }
    

4 个答案:

答案 0 :(得分:3)

IComparer<T>以及IEqualityComparer<T>使用两个 T实例,因此无需将其作为T类的一部分实现;但是,在IEqualityComparer<T>中实施T是一种很好的做法,该方案可以

  public partial class Test {
    private class TestComparer : IEqualityComparer<Test> {
      public bool Equals(Test x, Test y) { 
        return x.id == y.id && x.date == y.date; 
      }

      public int GetHashCode(Test obj) { 
        return obj.id.GetHashCode(); 
      }
    }

    // Please, note "static"
    public static IEqualityComparer<Test> MyTestComparer {get;} = new TestComparer();

    public int id { get; set; }
    public DateTime date { get; set; }
    ...
  }

在这种情况下,您只需使用您想要的比较器:

int distinctCountComparerClass = testList.Distinct(Test.MyTestComparer).Count();

答案 1 :(得分:3)

  

为什么不在课堂上实现呢?

因为没有意义。 IEqualityComparer<T>的完整目的是在T类型之外实施,因为它定位于帖子中的&#34;原因1&#34;

如果您希望类本身实现相等逻辑,那么您应该实现专门为此类场景提供的IEquatable<T>EqualityComparer<T>.Default将随时为您的实现提供必要的桥梁{需要{1}}并且未明确指定。

由于该类只能提供一个没有任何动态行为和/或选项的硬编码逻辑,因此它被认为是默认相等逻辑,因此静态名称{{1提供访问权限的属性。

答案 2 :(得分:2)

简单地说,通过这种方式,您可以根据上下文使用不同的方法来比较同一个类中的对象。

它基本上是控制反转:不是类本身决定另一个类可能想要比较它的实例。

答案 3 :(得分:0)

实现IEqualityComparer<T>而不是IEquatable<T>是一个好习惯,因为当类实现IEquatable<T>接口时,它会输入一个合同,其中规定“我知道如何比较类型为T或从T派生的任何类型的两个实例,以确保相等”。但是,如果派生该类,则基类不太可能知道如何进行有意义的比较。因此,该隐式合同现在被破坏了。

或者,可以将其实例设为comparable的类可以设为sealed,但是由于在此对话线程中已经说明了这些原因,所以另一种方法更为优雅。