【问题标题】:C# Compare Lists with custom object but ignore orderC# 将列表与自定义对象进行比较但忽略顺序
【发布时间】:2013-09-05 09:02:08
【问题描述】:

我正在尝试比较包含自定义对象的 2 个列表(包装在一个对象中)。 我不关心顺序,但如果列表 1 包含“1,2,3,4”,那么列表 2 必须并且仅包含这些元素。例如:“4,2,3,1”

基于Compare two List<T> objects for equality, ignoring order ignoring-order 我使用了 except 和 Any 但它没有给我想要的结果。

如果我使用Assert.Equals 会失败,但Assert.IsTry(list1.equals(list2)) 会成功。

如果我删除 Equals 和 GetHashCode 实现,那么这两个测试都会失败。

public class AppointmentCollection : List<Appointment>
{
    public override bool Equals(object obj)
    {            
        var appCol = obj as AppointmentCollection;

        if (appCol == null)
        {
            return false;
        }

        return (appCol.Count == this.Count) && !(this.Except(appCol).Any());
    }


    public override int GetHashCode()
    {
        unchecked
        {
            //use 2 primes
            int hash = 17;
            foreach (var appointment in this)
            {
                hash = hash * 19 + appointment.GetHashCode();
            }
            return hash;
        }
    }
}

public class Appointment
{
    public string Title {get; set;}
    public DateTime StartTime {get; set;}
    public DateTime EndTime { get; set;}

    public override bool Equals(object obj)
    {
        var appointment = obj as Appointment;
        if (appointment == null)
        {
            return false;
        }
        return Title.Equals(appointment.Title) &&
            StartTime.Equals(appointment.StartTime) &&
            EndTime.Equals(appointment.EndTime);
    }

    public override int GetHashCode()
    {
        unchecked
        {
            //use 2 primes
            int hash = 17;
            hash = hash * 19 + Title.GetHashCode();
            hash = hash * 19 + StartTime.GetHashCode();
            hash = hash * 19 + EndTime.GetHashCode();
            return hash;
        }
    }
}

[Test]
public void TestAppointmentListComparisonDifferentOrder()
{
    var appointment1 = new Appointment(
        "equals test1",
        new DateTime(2013, 9, 4),
        new DateTime(2013, 9, 4));

    var appointment2 = new Appointment(
        "equals test2",
        new DateTime(2013, 9, 4),
        new DateTime(2013, 9, 4));

    var list1 = new AppointmentCollection() { appointment1, appointment2 };
    var list2 = new AppointmentCollection() { appointment2, appointment1 };

    //With Equals/GetHashCode in AppointmentCollection implemented
    CollectionAssert.AreEqual(list1, list2); //fails
    Assert.IsTrue(list1.Equals(list2)); //success

    //Without Equals/GetHashCode in AppointmentCollection implemented
    CollectionAssert.AreEqual(list1, list2); //fails
    Assert.IsTrue(list1.Equals(list2)); //fails
}

【问题讨论】:

  • 骗子呢。 {2,2,1} 是否与 {1,2} 匹配?
  • @spender,不匹配(但现在这无关紧要,因为我们没有任何重复项。

标签: c# collections comparison nunit assert


【解决方案1】:

您没有明确说明您使用的是哪种单元测试工具。可能CollectionAssert 是类Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert,或者可能是NUnit.Framework.CollectionAssert,或者其他什么?

所以请检查您的测试工具的文档,或者在此处写下您使用的是哪一个。

但是,这很常见

CollectionAssert.AreEqual( ... );

检查集合是否相同顺序相同,而

CollectionAssert.AreEquivalent( ... );

会检查你想要什么。所以使用后者。

CollectionAssert 上的两种方法都没有实际使用您对 Equals(object) 的覆盖。要使用它,请写:

Assert.AreEqual( ... );

编辑:我认为Assert.AreEqual(exp, act); 总是会最终执行exp.Equals(act),这会调用您对AppointmentCollection 的覆盖。但事实证明,我们以私有 instance method EqualConstraint.ObjectsEqual 结尾,并且正如人们看到的那样,它检查运行时类型是否实现了 ICollection,在这种情况下,您的覆盖永远不会被使用。

经验教训:使用Assert.AreEqual 可能会与集合混淆。使用CollectionAssert.AreEquivalentCollectionAssert.AreEqual 明确您的意图。如果您只需要它进行测试,则不必在 AppointmentCollection 上覆盖 Equals。如果应用程序本身需要它并且想要对其进行测试,请按字面意思使用list1.Equals(list2) 编写测试,以确保测试的是您自己的覆盖。

(当然,在任何情况下都需要覆盖Appointment。)

【讨论】:

  • 对不起,它是 NUnit。我想知道为什么 AreEquals 和 IsTry+Equals 给出了不同的结果。因为如果我想签入代码(而不是在测试中),我需要知道比较是否正确。
  • @RvdK 你看到我更新的答案了吗? Assert.AreEqualCollectionAssert.AreEqual 不同。你的问题混淆了两者。第一个只是在集合上调用Equals 一次。这要求您覆盖AppointmentCollection。第二个遍历集合并在单个 Appointment 实例上调用 Equals。这不会使用您在 AppointmentCollection 上的覆盖(但会在 Appointment 上使用您的覆盖)。
  • Assert.AreEqual 在 AppointmentCollection 上无法正常运行的原因是什么?那么我的 GetHashCode 实现不正确吗?
  • @RvdK 你的代码没有检查Assert.AreEqual。你只使用CollectionAssert.AreEqual。我会说当Assert.IsTrue(list1.Equals(list2)) 可以时,Assert.AreEqual(list1, list2) 也可以。
  • 如果我使用'Assert.IsTrue(list1.Equals(list2));'它成功了,但如果我使用 'Assert.AreEqual(list1, list2);'它失败了。
猜你喜欢
  • 2019-05-11
  • 2015-10-23
  • 1970-01-01
  • 1970-01-01
  • 2022-01-05
  • 2018-04-06
  • 2021-08-31
  • 2018-11-04
  • 1970-01-01
相关资源
最近更新 更多