为什么我的Equals()的实现没有被AreEqual()调用?

本文关键字:AreEqual 调用 实现 我的 Equals 为什么 | 更新日期: 2023-09-27 18:02:29

我看过很多指令(Why does Assert.>AreEqual(T obj1, Tobj2)在相同的对象上失败,单元测试断言。AreEqual失败,Assert。AreEqual以相同类型失败)为我的类实现Equals/IEqualityComparer,如果我想根据字段值而不是引用检查是否相等。

在尝试这样做时,我无法使其工作,并将问题缩小到以下内容:

我的类Subject需要测试。在SubjectTestEqual中,我希望两个实例相等,但结果是"断言"。AreEqual失败了。此外,如果我调试代码,我看到没有调用EqualsGetHashCode

基于神秘化的"Default"属性检查类型T是否实现了System。接口,如果是,则返回使用该实现的EqualityComparer。否则,它返回一个使用Object的重写的EqualityComparer。等号和对象。GetHashCode由T.在equals比较器中提供。默认属性文档,我还尝试了IEquatable(取消注释代码以查看效果),但无济于事。

public class Subject : IEqualityComparer<Subject>//, IEquatable<Subject>
{
    public int Id { get; set; }
    public Subject(int name) { Id = name; }
    public bool Equals(Subject x, Subject y)
    { return (x.Id == y.Id); }
    public int GetHashCode(Subject obj)
    { return Id; }
    //public bool Equals(Subject other)
    //{ return Equals(this, other); }
}
[TestClass]
public class SubjectTest
{
    [TestMethod]
    public void SubjectTestEqual()
    { Assert.AreEqual<Subject>(new Subject(1), new Subject(1)); }
    [TestMethod]
    public void SubjectTestSame()
    {
        Subject test = new Subject(1);
        Assert.AreEqual<Subject>(test, test);
    }
}

有人能解释一下吗?

为什么我的Equals()的实现没有被AreEqual()调用?

您必须重写基方法才能调用您的方法:

public override bool Equals(object obj)
{ ... }
public override int GetHashCode()
{ ... }

但是您必须应用与EqualsGetHashcode基方法相同的签名。

谢谢你的回答,他们在这个问题上帮助了我,但没有一个能完全帮助我。

如果我像这样重写对象的Equals和GetHashCode方法:

public override bool Equals(object obj)
{ return true; }
public override int GetHashCode()
{ return 0; }

方法被调用,我的测试将成功。但是,当然,我不想为object类型的参数实现这些方法。为什么我的类要将实例与对象的任意实例进行比较?

因此,我将该方法修改为静态:public **static** bool Equals(Subject x, Subject y),并引入了一个新的测试方法(为简洁起见,所有测试都在一个方法中):
    [TestMethod]
    public void SubjectTestWithSubjectEquals()
    {
        Assert.IsTrue(Subject.Equals(new Subject(1), new Subject(1)));
        Assert.IsTrue(new Subject(1).Equals(new Subject(1)));
        Assert.IsFalse(Subject.Equals(new Subject(1), new Subject(2)));
        Assert.IsFalse(new Subject(1).Equals(new Subject(2)));
    }

这些测试将成功。然而,我不确定这是否是一个好方法。首先,要使Assert.IsTrue((new Subject(1)) == (new Subject(1)));成功,我需要实现:

public static bool operator ==(Subject x, Subject y)
    { return Equals(x, y); }

,这也需要:

public static bool operator !=(Subject x, Subject y)
    { return !Equals(x, y); }

同时,更进一步,希望能够比较Subject类型的列表,我尝试了这个测试:

[TestMethod]
public void SubjectTestWithCollections()
{
    var list1 = new List<Subject>() { new Subject(1), new Subject(2) };
    var list2 = new List<Subject>() { new Subject(1), new Subject(2) };
    CollectionAssert.AreEqual(list1, list2);
}

将失败,因为显然,每个项将使用Assert进行比较。平等,而不是主体。平等。我看到了CollectionAssert的问题。AreEquivalent,这让我怀疑这是否主要是由Microsoft.VisualStudio.TestTools.UnitTesting实现的方式引起的,或者我不应该试图在一般情况下为Equals而困扰。

您的TestClass违反了Object.Equals的合同。Assert.AreEqual依赖于这个契约,这是相当合理的。

文档状态(在需求列表中):

x。Equals(null引用(在Visual Basic中是Nothing))返回false。

Assert.AreEqual将独占地使用传入的第一个参数的Equals方法。它现在知道你的IEqualityComparer实现,所以它不会被使用。

通常,当一个类需要比较对象是否相等时,它会有一个IEqualityComparer的可选参数,类可以用它来代替对象本身的Equals方法来进行比较,但是Assert.AreEqual不接受这样的参数。这意味着要使用Assert.AreEqual,您需要覆盖从object继承的Equals方法,即:

public override bool Equals(object obj){}

一个类型实现它自己的类型的IEqualityComparer 是没有什么意义的。IEqualityComparer的思想是它允许你比较与其他类型是否相等,而不是"你自己"。