联合两个自定义类返回重复项
我有两个自定义类,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);
}
编辑:< /strong> 我在 ChangeRequest
和 ChangeRequests
上覆盖了 GetHashCode
,但仍在测试中,如果我执行 IEnumerable
,unionedCRsIEnum
最终得到 ChangeRequest
的两个副本,CRID
为 12
编辑:某些东西必须与我的Equals
或GetHashCode
实现相一致,因为Assert.AreEqual(expected, unionedCRs.Distinct) (), "Distinct 应删除重复项");
失败,expected
和 unionedCRs.Distinct()
的字符串表示形式显示 unionedCRs. Distinct()
肯定有 CR 12 的两个副本。
I have two custom classes, ChangeRequest
and ChangeRequests
, where a ChangeRequests
can contain many ChangeRequest
instances.
public class ChangeRequests : IXmlSerializable, ICloneable, IEnumerable<ChangeRequest>,
IEquatable<ChangeRequests> { ... }
public class ChangeRequest : ICloneable, IXmlSerializable, IEquatable<ChangeRequest>
{ ... }
I am trying to do a union of two ChangeRequests
instances. However, duplicates do not seem to be removed. My MSTest unit test is as follows:
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");
The test fails in the last line, and unionedCRs
contains two copies of cr1
. When I tried to debug and step through each line, I had a breakpoint in ChangeRequest.Equals(object)
on the first line, as well as in the first line of ChangeRequest.Equals(ChangeRequest)
, but neither were hit. Why does the union contain duplicate ChangeRequest
instances?
Edit: as requested, here is ChangeRequests.Equals(ChangeRequests)
:
public bool Equals(ChangeRequests other)
{
if (ReferenceEquals(this, other))
{
return true;
}
return null != other && this.SequenceEqual<ChangeRequest>(other);
}
And here's ChangeRequests.Equals(object)
:
public override bool Equals(object obj)
{
return Equals(obj as ChangeRequests);
}
Edit: I overrode GetHashCode
on both ChangeRequest
and ChangeRequests
but still in my test, if I do IEnumerable<ChangeRequest> unionedCRsIEnum = crs1.Union<ChangeRequest>(crs2);
, unionedCRsIEnum
ends up with two copies of the ChangeRequest
with CRID
12.
Edit: something has to be up with my Equals
or GetHashCode
implementations somewhere, since Assert.AreEqual(expected, unionedCRs.Distinct(), "Distinct should remove duplicates");
fails, and the string representations of expected
and unionedCRs.Distinct()
show that unionedCRs.Distinct()
definitely has two copies of CR 12.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
确保您的
GetHashCode
实现与您的Equals
一致 -Enumerable.Union
方法似乎确实使用了两者。如果您实现了其中一个但没有实现另一个,您应该会收到编译器的警告;您仍然需要确保这两种方法彼此一致。以下是规则的方便摘要:为什么在重写 Equals 方法时重写 GetHashCode 很重要?
Make sure your
GetHashCode
implementation is consistent with yourEquals
- theEnumerable.Union
method does appear to use both.You should get a warning from the compiler if you've implemented one but not the other; it's still up to you to make sure that both methods agree with each other. Here's a convenient summary of the rules: Why is it important to override GetHashCode when Equals method is overridden?
我不相信
Assert.AreEqual()
检查序列的内容 - 它比较序列对象本身,它们显然不相等。您需要的是一个
SequenceEqual()
方法,它将实际检查两个序列的内容。 这个答案可能对您有帮助。这是对类似问题的回答,描述了如何与IEnumerable
序列进行比较。您可以轻松地获取响应者的答案,并创建一个扩展方法以使调用看起来更像断言:
或者您可以使用
SequenceEqual()
,比较序列,意识到它不会提供任何关于哪些元素不相等的信息。I don't believe that
Assert.AreEqual()
examines the contents of the sequence - it compares the sequence objects themselves, which are clearly not equal.What you want is a
SequenceEqual()
method, that will actually examine the contents of two sequences. This answer may help you. It's a response to a similar question, that describes how to compare toIEnumerable<>
sequences.You could easily take the responder's answer, and create an extension method to make the calls look more like assertions:
Alternatively you could use
SequenceEqual()
, to compare the sequences, realizing that it won't provide any information about which elements are not equal.正如 LBushkin 所说,
Assert.AreEqual
只会在序列上调用Equals
。您可以使用
SequenceEqual
扩展方法不过:但是,如果失败的话,这不会提供太多信息。
您可能需要使用我们为 MoreLINQ 编写的测试代码,该代码是序列-focused - 如果序列不相等,它将指定它们的不同之处。 (我试图获取相关源文件的链接,但我的网络连接很糟糕。)
As LBushkin says,
Assert.AreEqual
will just callEquals
on the sequences.You can use the
SequenceEqual
extension method though:That won't give much information if it fails, however.
You may want to use the test code we wrote for MoreLINQ which was sequence-focused - if the sequences aren't equal, it will specify in what way they differ. (I'm trying to get a link to the source file in question, but my network connection is rubbish.)