【问题标题】:What does System.Collections.Generic.Dictionary<T,T>.Equals actually do?System.Collections.Generic.Dictionary<T,T>.Equals 实际上做了什么?
【发布时间】:2008-12-22 22:20:02
【问题描述】:

我今天在对通用字典进行单元测试时遇到了这个问题。

System.Collections.Generic.Dictionary<int, string> actual, expected;
actual = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
expected = new System.Collections.Generic.Dictionary<int, string> { { 1, "foo" }, { 2, "bar" } };
Assert.AreEqual(expected, actual); //returns false

失败,除非actual == expected(对象引用相同)。显然,actual.Equals(expected) 也返回 false。

很好,但是如果System.Collections.Generic.Dictionary&lt;int, string&gt;.Equals 的实现只是引用相等,那么IEquatable 的意义何在?换句话说,为什么没有内置的方法来为泛型集合进行值相等?

编辑感谢您迄今为止的回复。显然我的例子是使用值类型,但我认为我的抱怨适用于所有对象。为什么泛型集合相等性不能只是其类型相等性的并集?意外的行为并没有真正削减它,因为有单独的规定来寻找参考平等。正如 Konrad Rudolph 指出的那样,我想这将引入集合的约束,即仅持有实现 IEquatable 的对象。但是,在 Dictionary 这样的对象中,这似乎并不过分。

【问题讨论】:

    标签: c# generics collections comparison equality


    【解决方案1】:

    换句话说,为什么没有内置的方法来为泛型集合进行值相等?

    可能是因为很难用通用术语来表述,因为这只有在字典的值类型(和键类型)也实现IEquatable 时才有可能。但是,这样的要求太强了,使得Dictionary 无法用于许多未实现此接口的类型。

    这是受限泛型的固有问题。 Haskell 为这个问题提供了解决方案,但这需要更强大和更复杂的泛型机制。

    请注意,与容器相比,IComparable 也有类似的情况,但支持这一点,如有必要,请使用 Comparer&lt;T&gt;.Default。

    【讨论】:

      【解决方案2】:

      Dictionary&lt;T,T&gt;.Equals 继承自 Object.Equals,因此对对象引用进行了简单的比较。

      为什么泛型集合不做值相等语义?因为那可能不是你想要的。有时您想检查它们是否是同一个实例。替代方案会做什么?在每个键和值上调用 Equals?如果这些从 Object 继承 Equals 怎么办?这不会是一个完整的深度比较。

      因此,如果有必要,您可以提供一些其他语义。

      【讨论】:

      • 另外,如果我们有一个包含自身的对象字典怎么办?我们可能首先会被一群程序员杀死,但最终可能会陷入无限循环。
      • 另一种选择是提供一个理智的、一致的相等操作语义,而不是现在的汞合金。除非我深入研究继承堆栈,否则无法判断 Equals() 实际上等于什么!
      【解决方案3】:

      Dictionary&lt;TKey, TValue&gt; 没有实现 IEquatable,因此没有正式的方法来确定/知道将一个这样的字典与另一个具有相同内容的字典进行比较会产生什么结果。

      事实上,Dictionary&lt;TKey, TValue&gt; 根本没有实现任何比较接口。

      在我看来,让两个对象相互比较是一件相当特殊的事情,因此将其放入接口中比在基 Object 类中放入默认的通常不需要的实现更有意义。它应该是一个类的一个比每个对象都可以做的更广为宣传的特性,尽管它不是你期望的那样。

      但是你有它。它就在那里,你需要知道它什么时候会被使用。

      就像在这种情况下。

      【讨论】:

      • 您可以注意到,像 NUnit 这样的测试框架提供了使用诸如 myDictionary.Is.EqualTo(otherDictionary) 之类的简单事物的方法,这些事物将使用 ICollection 接口。
      • 没错,但这是单元测试框架的 .EqualTo 方法内置的代码,而不是集合类本身内置的代码。如果您将外部代码添加到组合中,您当然可以做任何您想做的事情。
      • 同意:通常不需要的实现。公平点说 Dictionary 根本没有实现任何比较接口(我责怪 MSDN 让我在这一点上感到困惑“如果类型 TKey 实现 System.IEquatable(T) 泛型接口,则默认相等比较器使用该实现。”
      • 另请注意,一个 Dictionary 实例能够 100% 将自身与另一个实例进行比较的唯一方法是,如果 TKey 和 TValue 都实现了其中一个比较接口,因此它将不得不添加限制,只接受这样做的泛型类型。
      猜你喜欢
      • 1970-01-01
      • 2013-06-02
      • 2020-11-21
      • 2015-02-26
      • 2017-06-29
      • 2013-06-13
      • 2021-10-25
      • 2011-08-12
      • 1970-01-01
      相关资源
      最近更新 更多