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

C# 为什么我的Equals()实现没有被AreEqual()调用,c#,c#-4.0,C#,C# 4.0,如果我想基于字段值而不是引用检查相等性,我已经看到了许多指令(,)来为我的类实现相等/IEqualityComparer 在尝试这样做时,我无法让它工作,并将问题缩小到以下方面 我班的科目需要考试。在SubjectTestEqual中,我希望这两个实例相等,但结果是“Assert.AreEqual失败。此外,如果我调试代码,我看不到对Equals或GetHashCode的调用 根据神秘化的“默认属性”检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的Equali

如果我想基于字段值而不是引用检查相等性,我已经看到了许多指令(,)来为我的类实现
相等
/
IEqualityComparer

在尝试这样做时,我无法让它工作,并将问题缩小到以下方面

我班的科目需要考试。在SubjectTestEqual中,我希望这两个实例相等,但结果是“Assert.AreEqual失败。此外,如果我调试代码,我看不到对Equals或GetHashCode的调用

根据神秘化的“默认属性”检查类型T是否实现System.IEquatable接口,如果是,则返回使用该实现的EqualityComparer。否则,它将返回一个EqualityComparer,使用T提供的Object.Equals和Object.GetHashCode的重写。”在中,我还尝试了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);
    }
}
公共类主题:IEqualityComparer/,IEquatable
{
公共int Id{get;set;}
公共主题(int name){Id=name;}
公共布尔等于(主体x、主体y)
{return(x.Id==y.Id);}
公共int GetHashCode(主题obj)
{返回Id;}
//公共布尔等于(受试者其他)
//{返回等于(这个,其他);}
}
[测试类]
公开课科目测验
{
[测试方法]
public void SubjectTestEqual()
{Assert.AreEqual(新主语(1),新主语(1));}
[测试方法]
public void SubjectTestSame()
{
科目测试=新科目(1);
断言.AreEqual(测试,测试);
}
}

有人能解释一下吗?

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

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

public override int GetHashCode()
{ ... }

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

您的测试类违反了
对象的约定。Equals
断言。AreEqual
非常合理地依赖于该约定

单据状态(需求清单):


x、 Equals(一个空引用(Visual Basic中没有任何内容))返回false。

Assert.AreEqual
将专门使用传入的第一个参数的
Equals
方法。它现在知道了
IEqualityComparer
实现,因此不会使用它

通常,当类需要比较对象是否相等时,它将有一个可选参数
IEqualityComparer
,该类可以使用该参数来进行比较,而不是对象本身的
Equals
方法,但是
Assert.arequal
不接受此类参数。这意味着使用
Assert.arequal>l
您需要重写从
对象继承的
Equals
方法,即:

公共覆盖布尔等于(对象obj){}


对于一个类型来说,实现它自己类型的
IEqualityComparer
没有什么意义。
IEqualityComparer
的想法是它允许你比较其他类型的平等性,而不是“你自己”。谢谢你的回答,他们在这方面帮助了我,但没有一个完全帮助了我

如果我重写对象的Equals和GetHashCode方法,如下所示:

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

public override int GetHashCode()
{ return 0; }
方法被调用,我的测试将成功。但是,当然,我不想为object类型的参数实现这些方法。为什么我的类只提供将实例与object的任何实例进行比较

因此,我将此方法修改为静态:
public**static**bool Equals(受试者x,受试者y)
,并引入了一种新的测试方法(为了简洁起见,所有测试都集中在一个方法中):

这些测试将会成功。但是,我不确定这是否是一个好的继续进行的方法。首先,对于
Assert.IsTrue((新主题(1))==(新主题(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); }
此外,更进一步,为了能够比较类型主题的列表,我尝试了以下测试:

[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);
}
[TestMethod]
public void SubjectTestWithCollections()
{
var list1=new List(){new Subject(1),new Subject(2)};
var list2=new List(){new Subject(1),new Subject(2)};
集合资产等于(列表1、列表2);
}

这将失败,因为很明显,每个项目都将使用Assert.AreEqual而不是Subject.Equals进行比较。我已经看到了,这让我想知道这是否主要是由Microsoft.VisualStudio.TestTools.UnitTesting的实现方式造成的,或者我不应该试着在一般情况下对Equals大惊小怪。

Object.Equals的“契约”是什么签名?你为什么选择文档中的引用?我没有传递任何空值。我只是添加了:IEqualityComparer,从来没有为签名操心过。我应该注意到,我没有被警告使用覆盖任何基本方法。我正在尝试掌握这一点。我使用的是通用版本的“public static void AreEqual”(不是预期的,不是实际的)’。因此,传入的第一个参数是Subject类型。感谢您澄清了IEqualityComparer的含义。如果我理解正确,在Subject上实现IEqualityComparer将允许我比较Subject实例和Subject2实例。@R.Schreurs不,更多的是
IEqualityComparer
允许您比较两个类当您无法控制
Equals
的定义时,或者当可能存在多个定义时。因此,您可能希望在中创建一个
IEqualityComparer
,进行不区分大小写的比较,或者编写一个
IEqualityComparer
,根据列表中的值而不是列表等等。根据其他答案,我得出了一些答案。见下文。
[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);
}