Vb.net CollectionAssert.AreEqual通过但CollectionAssert.Areequality失败?
我已经构建了一些复杂的对象,我正在尝试通过一些单元测试来验证它是否正常工作。这涉及到比较一些列表(T),所以我尝试使用CollectionAssert。 现在我遇到了一些奇怪的事情 首先,我使用CollectionAssert.AreEqual查看第一个列表是否相等。这一主张获得通过。但是为了简单起见,我想使用CollectionAssert.AreEqual,这样我就不必按照正确的顺序创建预期的对象,所以我开始尝试。使用完全相同的代码,CollectionAssert.AreEquivalent失败。我会说这很奇怪,因为等价是一个比相等更松散的断言,对吗?我得到这个错误:Vb.net CollectionAssert.AreEqual通过但CollectionAssert.Areequality失败?,vb.net,unit-testing,assert,Vb.net,Unit Testing,Assert,我已经构建了一些复杂的对象,我正在尝试通过一些单元测试来验证它是否正常工作。这涉及到比较一些列表(T),所以我尝试使用CollectionAssert。 现在我遇到了一些奇怪的事情 首先,我使用CollectionAssert.AreEqual查看第一个列表是否相等。这一主张获得通过。但是为了简单起见,我想使用CollectionAssert.AreEqual,这样我就不必按照正确的顺序创建预期的对象,所以我开始尝试。使用完全相同的代码,CollectionAssert.AreEquivalen
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进行比较,所以这意味着我将基本上实现此功能两次,以确保相等的对象获得相同的哈希代码,对吗?这感觉很奇怪…好吧,这确实和我想的一样。然而,我不太明白的是,面对哈希冲突,如何使用哈希代码作为字典的键。这不意味着我可以为同一个密钥输入两个条目吗?(不管机会有多渺茫)没关系,我刚刚明白你关于词典用法的观点。谢谢,这才是真正的澄清。