联合两个自定义类返回重复项

发布于 2024-09-06 23:27:15 字数 2410 浏览 4 评论 0原文

我有两个自定义类,ChangeRequestChangeRequests,其中 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> 我在 ChangeRequestChangeRequests 上覆盖了 GetHashCode,但仍在测试中,如果我执行 IEnumerableunionedCRsIEnum = crs1.Union(crs2);unionedCRsIEnum 最终得到 ChangeRequest 的两个副本,CRID 为 12

编辑:某些东西必须与我的EqualsGetHashCode实现相一致,因为Assert.AreEqual(expected, unionedCRs.Distinct) (), "Distinct 应删除重复项"); 失败,expectedunionedCRs.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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

浅听莫相离 2024-09-13 23:27:15

确保您的 GetHashCode 实现与您的 Equals 一致 - Enumerable.Union 方法似乎确实使用了两者。

如果您实现了其中一个但没有实现另一个,您应该会收到编译器的警告;您仍然需要确保这两种方法彼此一致。以下是规则的方便摘要:为什么在重写 Equals 方法时重写 GetHashCode 很重要?

Make sure your GetHashCode implementation is consistent with your Equals - the Enumerable.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?

So尛奶瓶 2024-09-13 23:27:15

我不相信 Assert.AreEqual() 检查序列的内容 - 它比较序列对象本身,它们显然不相等。

您需要的是一个 SequenceEqual() 方法,它将实际检查两个序列的内容。 这个答案可能对您有帮助。这是对类似问题的回答,描述了如何与 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(),比较序列,意识到它不会提供任何关于哪些元素不相等的信息。

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 to IEnumerable<> sequences.

You could easily take the responder's answer, and create an extension method to make the calls look more like assertions:

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); 
    }
  }
}

Alternatively you could use SequenceEqual(), to compare the sequences, realizing that it won't provide any information about which elements are not equal.

合约呢 2024-09-13 23:27:15

正如 LBushkin 所说,Assert.AreEqual 只会在序列上调用 Equals

您可以使用 SequenceEqual 扩展方法不过:

Assert.IsTrue(expected.SequenceEqual(unionedCRs));

但是,如果失败的话,这不会提供太多信息。

您可能需要使用我们为 MoreLINQ 编写的测试代码,该代码是序列-focused - 如果序列不相等,它将指定它们的不同之处。 (我试图获取相关源文件的链接,但我的网络连接很糟糕。)

As LBushkin says, Assert.AreEqual will just call Equals on the sequences.

You can use the SequenceEqual extension method though:

Assert.IsTrue(expected.SequenceEqual(unionedCRs));

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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文