C#比较列表与自定义对象,但忽略顺序 [英] C# Compare Lists with custom object but ignore order

查看:182
本文介绍了C#比较列表与自定义对象,但忽略顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图比较包含自定义对象的2个列表(包含在一个对象中)。
我不在乎顺序,但如果列表1包含1,2,3,4,则列表2必须且仅包含这些元素。例如:4,2,3,1



基于比较两个列表< T>对象的平等,忽略顺序
忽略顺序我使用了Except和任何,但它不给我想要的结果。



如果我使用 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()
{
取消选中
{
//使用2个原子
int hash = 17;
foreach(var appointment in this)
{
hash = hash * 19 + appointment.GetHashCode();
}
return hash;
}
}
}

public class预约
{
public string标题{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()
{
取消选中
{
//使用2个原子
int hash = 17;
hash = hash * 19 + Title.GetHashCode();
hash = hash * 19 + StartTime.GetHashCode();
hash = hash * 19 + EndTime.GetHashCode();
return hash;
}
}
}

[测试]
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};

//在AppointmentCollection中的Equals / GetHashCode实现
CollectionAssert.AreEqual(list1,list2); // failed
Assert.IsTrue(list1.Equals(list2)); // success

//在AppointmentCollection中不带Equals / GetHashCode
CollectionAssert.AreEqual(list1,list2); // failed
Assert.IsTrue(list1.Equals(list2)); // failed
}


解决方案

t清楚地说明您使用的单元测试工具。可能 CollectionAssert 是类 Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert ,也许是 NUnit.Framework.CollectionAssert ,或者可能是其他内容? / p>

因此,请检查您的测试工具的文档,或在这里写下您使用的测试工具。



常用于

  CollectionAssert.AreEqual(...); 

检查集合是否以相同顺序相同

  CollectionAssert.AreEquivalent(...); 

会检查您想要的内容。



CollectionAssert 上的两个方法实际上都不会覆盖 Equals(object)。要使用它,请写:

  Assert.AreEqual(...); 

编辑:我认为 Assert.AreEqual exp.Equals(act)会调用你的覆写 AppointmentCollection / code>。但事实证明,我们在私人实例方法 EqualConstraint.ObjectsEqual ,并且看到它检查运行时类型是否实现 ICollection ,在这种情况下您的覆盖是从未使用过。



经验教训:使用 Assert.AreEqual 可能会与集合混淆。使用 CollectionAssert.AreEquivalent CollectionAssert.AreEqual 来明确您的意图。如果你只需要它来测试,你不必重写等于在 AppointmentCollection 。如果你需要它的应用程序本身,你想测试,写测试与 list1.Equals(list2)字面上确保自己的覆盖是被测试。



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


I'm trying to compare 2 Lists (wrapped in an object) containing custom objects. I don't care about the order, but if list 1 contains "1,2,3,4" then list 2 must and only contain those elements. E.g.: "4,2,3,1"

Based on Compare two List<T> objects for equality, ignoring order ignoring-order I've used the Except and Any but it doesn't give me the desired results.

If I use Assert.Equals it fails, but Assert.IsTry(list1.equals(list2)) succeeds.

Further more if I remove the Equals and GetHashCode implementation then both tests fail.

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
}

解决方案

You didn't state clearly which unit test tool you use. Maybe CollectionAssert is the class Microsoft.VisualStudio.TestTools.UnitTesting.CollectionAssert, or maybe it is NUnit.Framework.CollectionAssert, or maybe something else?

So check the documentation of your testing tool, or write here which one you use.

However, it is common for

CollectionAssert.AreEqual( ... );

to check if the collections are the same in the same order, while

CollectionAssert.AreEquivalent( ... );

will check what you want. So use the latter.

Neither of the two methods on CollectionAssert actually uses your override of Equals(object). To use that, write:

Assert.AreEqual( ... );

Edit: I thought Assert.AreEqual(exp, act); would always end up doing exp.Equals(act) which would call your override on AppointmentCollection. But it turns out we end in the private instance method EqualConstraint.ObjectsEqual, and as one sees it checks if the run-time type implements ICollection in which case your override is never used.

Lesson learned: Using Assert.AreEqual can be confusing with collections. Use CollectionAssert.AreEquivalent or CollectionAssert.AreEqual to make your intention clear. You don't have to override Equals on AppointmentCollection if you only need it for testing. If you need it for the application itself and you want to test that, write the test with list1.Equals(list2) literally to make sure your own override is what is tested.

(In any case the override on Appointment is needed, of course.)

这篇关于C#比较列表与自定义对象,但忽略顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆