繁体   English   中英

为什么要实现 IEqualityComparer<T> 在一个单独的班级

[英]Why implement IEqualityComparer<T> in a separate class

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

我能想象重写object.Equalsobject.GetHashCode ,因为它在很多不同的情况下使用不被认为是很好的做法,但即使MSDN说(重点煤矿):

此接口允许为集合实现自定义的相等性比较。

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

  1. 类集合上的不同方法需要不同的比较器。
  2. 这个类很大,不希望实例化它的另一个对象(尽管如果这真的是问题,为什么不拥有一个完整的集合还不错?)。

所以我的问题是:

是否有任何我忽略的特殊原因导致每个人定义另一个比较器类只是为了比较而不是仅仅在类本身上实现接口(至少在我看来这不会更糟)?

一个小例子:

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(); }
}

为什么不在类本身上实现它?

因为没有意义。 IEqualityComparer<T>的全部目的是在类型T之外实现,因为它针对您帖子中的“原因 1”

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

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

IComparer<T>IEqualityComparer<T>IEqualityComparer<T>两个实例一起工作,因此它们不需要作为T类的一部分来实现; 然而,在T实现IEqualityComparer<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();

简而言之,通过这种方式,您可以根据上下文使用不同的方法来比较来自同一类的对象。

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

实现IEqualityComparer<T>而不是IEquatable<T>是一个很好的做法,因为当一个类实现IEquatable<T>接口时,它会进入一个契约,其中声明“我知道如何比较两个T类型的实例或从T派生的任何类型的相等性”。 但是,如果该类是派生的,则基类不太可能知道如何进行有意义的比较。 因此,该隐性合同现在已被打破。

或者,我们希望将其实例进行comparable的类可以被sealed ,但由于本对话线程中已经说明的原因,另一种方法要优雅得多。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM