Vb.net CollectionAssert.AreEqual通过但CollectionAssert.Areequality失败?

Vb.net CollectionAssert.AreEqual通过但CollectionAssert.Areequality失败?,vb.net,unit-testing,assert,Vb.net,Unit Testing,Assert,我已经构建了一些复杂的对象,我正在尝试通过一些单元测试来验证它是否正常工作。这涉及到比较一些列表(T),所以我尝试使用CollectionAssert。 现在我遇到了一些奇怪的事情 首先,我使用CollectionAssert.AreEqual查看第一个列表是否相等。这一主张获得通过。但是为了简单起见,我想使用CollectionAssert.AreEqual,这样我就不必按照正确的顺序创建预期的对象,所以我开始尝试。使用完全相同的代码,CollectionAssert.AreEquivalen

我已经构建了一些复杂的对象,我正在尝试通过一些单元测试来验证它是否正常工作。这涉及到比较一些列表(T),所以我尝试使用CollectionAssert。 现在我遇到了一些奇怪的事情

首先,我使用CollectionAssert.AreEqual查看第一个列表是否相等。这一主张获得通过。但是为了简单起见,我想使用CollectionAssert.AreEqual,这样我就不必按照正确的顺序创建预期的对象,所以我开始尝试。使用完全相同的代码,CollectionAssert.AreEquivalent失败。我会说这很奇怪,因为等价是一个比相等更松散的断言,对吗?我得到这个错误:

CollectionAssert.AreEquivalent failed. The expected collection contains 1 occurrence(s) of <MyObject>. The actual collection contains 0 occurrence(s).
CollectionAssert.AreEquivalent失败。预期的集合包含1次出现的。实际集合包含0个事件。
我尝试过调试,但调试.Net framework时无法正常工作,即使我设置了下载符号文件。因此,我只能看到它进入我的自定义Equals函数一次——返回true——然后断言失败。两个对象都有两个元素。调用堆栈是(按相反顺序):

  • CollectionAssert.AreEquivalent
  • CollectionAssert.AreEquivalent(过载)
  • CollectionAssert.FindMisMatchedElement
  • Generic.Dictionary(对象的,int).TryGetValue
  • Generic.Dictionary(对象的,int).FindEntry
  • Generic.ObjectEqualityComparer.Equals
  • 我的习惯等于

现在我正在写这篇文章,一个想法出现了,我看到了一个潜在的问题。我看到它内部使用字典。它可能起到某种hashmap的作用,其中int是实际列表中的索引?这是否意味着我需要实现一个定制的IEqualityComparer,而不是覆盖equals?那么我的getHashCode()应该是什么样子呢?(我猜这是至关重要的,因为我认为它可能用于字典中的键?

你的思路是对的:问题确实是你在重写
等于
时没有重写
GetHashCode

下面是一个重现您的问题的示例:

void Main()
{
    var a = new []{new Broken{Foo="a"}, new Broken{Foo="b"}};
    var b = new []{new Broken{Foo="a"}, new Broken{Foo="b"}};

    CollectionAssert.AreEqual(a, b);
    CollectionAssert.AreEquivalent(a, b);
}

class Broken
{
    public string Foo {get;set;}

    public override bool Equals(object obj)
    {
        return Foo == ((Broken)obj).Foo;
    }
}
正如您正确指出的,
CollectionAssert.arequivalent
使用一个
字典
,它用于计算集合中每个唯一元素的频率

问题不在于hashcode可能发生冲突,而是如果两个应该被视为相等的元素实际上从未使用
Equals
进行比较,那么
GetHashCode
返回的hashcode是不同的


您也可能对这个问题感兴趣:


另外,我的equals函数中有一些逻辑,它不是直接将所有字符串1对1进行比较,所以这意味着我将基本上实现此功能两次,以确保相等的对象获得相同的哈希代码,对吗

不一定。
字典
的性能取决于哈希算法(当对象用作键时,其哈希值也不应改变)

如果您可以忍受一些性能损失(可能可以忽略不计),那么可以使用比
Equals
方法更简单的方法来计算哈希值(并接受更多的哈希冲突)。如果两个对象的哈希值相等,则仍将调用
Equals
。(事实上,您可以只返回相同的值,例如每次返回1)


文件中的相关章节:

在哈希表对象中用作键的对象也必须重写GetHashCode方法,因为这些对象必须生成自己的哈希代码

如果两个对象的比较结果相等,则每个对象的GetHashCode方法必须返回相同的值。但是,如果两个对象的比较结果不相等,则两个对象的GetHashCode方法不必返回不同的值


你有没有可能在你的类中重写了
Equals
,而不是
GetHashCode
?如果你展示你的代码,这会更容易回答。我理解,但在这种情况下,这是相当多的代码。正如我在最后一段中提到的,我确实没有重写GetHashCode。但我还不太明白的是我的GetHashCode应该是什么样子。t类基本上包含4个字符串和一个枚举类型。我不太明白的是它需要GetHashCode做什么。在我写的时候,我想它可能是那本字典的钥匙。但是,哈希代码可能有冲突,对吗?另外,我的equals函数中有一些逻辑,它不是直接将所有字符串1对1进行比较,所以这意味着我将基本上实现此功能两次,以确保相等的对象获得相同的哈希代码,对吗?这感觉很奇怪…好吧,这确实和我想的一样。然而,我不太明白的是,面对哈希冲突,如何使用哈希代码作为字典的键。这不意味着我可以为同一个密钥输入两个条目吗?(不管机会有多渺茫)没关系,我刚刚明白你关于词典用法的观点。谢谢,这才是真正的澄清。