我有两个自定义类ChangeRequest
和ChangeRequests
,其中ChangeRequests
可以包含许多ChangeRequest
个实例。
public class ChangeRequests : IXmlSerializable, ICloneable, IEnumerable<ChangeRequest>,
IEquatable<ChangeRequests> { ... }
public class ChangeRequest : ICloneable, IXmlSerializable, IEquatable<ChangeRequest>
{ ... }
我正在尝试组合两个ChangeRequests
个实例。但是,似乎没有删除重复项。我的MSTest单元测试如下:
var cr1 = new ChangeRequest { CRID = "12" };
var crs1 = new ChangeRequests { cr1 };
var crs2 = new ChangeRequests
{
cr1.Clone(),
new ChangeRequest { CRID = "34" }
};
Assert.AreEqual(crs1[0], crs2[0], "First CR in both ChangeRequests should be equal");
var unionedCRs = new ChangeRequests(crs1.Union<ChangeRequest>(crs2));
ChangeRequests expected = crs2.Clone();
Assert.AreEqual(expected, unionedCRs, "Duplicates should be removed from a Union");
测试在最后一行失败,unionedCRs
包含cr1
的两个副本。当我尝试调试并逐步执行每一行时,我在ChangeRequest.Equals(object)
的第一行以及ChangeRequest.Equals(ChangeRequest)
的第一行中有一个断点,但都没有被击中。为什么联合包含重复的ChangeRequest
个实例?
修改,这里是ChangeRequests.Equals(ChangeRequests)
:
public bool Equals(ChangeRequests other)
{
if (ReferenceEquals(this, other))
{
return true;
}
return null != other && this.SequenceEqual<ChangeRequest>(other);
}
这里是ChangeRequests.Equals(object)
:
public override bool Equals(object obj)
{
return Equals(obj as ChangeRequests);
}
修改:我在GetHashCode
和ChangeRequest
上覆盖了ChangeRequests
,但仍在我的测试中,如果我IEnumerable<ChangeRequest> unionedCRsIEnum = crs1.Union<ChangeRequest>(crs2);
,{{1}最终得到unionedCRsIEnum
ChangeRequest
12的两份副本。
修改:我的CRID
或Equals
实施在某处,因为GetHashCode
失败,以及{{1}的字符串表示形式。 }和Assert.AreEqual(expected, unionedCRs.Distinct(), "Distinct should remove duplicates");
表明expected
肯定有两份CR 12。
答案 0 :(得分:4)
确保您的GetHashCode
实施与Equals
一致 - Enumerable.Union
方法似乎同时使用这两种方法。
如果你已经实现了一个而不是另一个,你应该收到编译器的警告;你仍然需要确保两种方法相互一致。以下是规则的简单摘要:Why is it important to override GetHashCode when Equals method is overridden?
答案 1 :(得分:3)
我不相信Assert.AreEqual()
检查序列的内容 - 它比较序列对象本身,这显然是不相等的。
你想要的是SequenceEqual()
方法,它实际上会检查两个序列的内容。 This answer may help you。这是对类似问题的回答,描述了如何与IEnumerable<>
序列进行比较。
您可以轻松获取响应者的答案,并创建一个扩展方法,使调用看起来更像断言:
public static class AssertionExt
{
public static bool AreSequencesEqual<T>( IEnumerable<T> expected,
IEnumerable<T> sequence )
{
Assert.AreEqual(expected.Count(), sequence .Count());
IEnumerator<Token> e1 = expected.GetEnumerator();
IEnumerator<Token> e2 = sequence .GetEnumerator();
while (e1.MoveNext() && e2.MoveNext())
{
Assert.AreEqual(e1.Current, e2.Current);
}
}
}
或者您可以使用SequenceEqual()
来比较序列,意识到它不会提供有关哪些元素不相等的任何信息。
答案 2 :(得分:0)
正如LBushkin所说,Assert.AreEqual
只会在序列上调用Equals
。
您可以使用SequenceEqual
扩展名方法:
Assert.IsTrue(expected.SequenceEqual(unionedCRs));
然而,如果它失败,那将不会提供太多信息。
您可能想要使用以序列为中心的test code we wrote for MoreLINQ - 如果序列不相等,它将指定它们的不同之处。 (我正在尝试获取有问题的源文件的链接,但我的网络连接是垃圾。)