对于以其他类的对象为成员的类,应该如何实现相等性检查?

How should I implement equality checking for classes that have objects of other classes as member?

提问人:isakgo_ 提问时间:7/11/2022 更新时间:7/11/2022 访问量:68

问:

我有一个类,它有一个类的对象。StudentName

此时,类的相等性检查返回false,我不知道为什么。Student

public class Student : IEquatable<Student>
{
  public Name Name { get; }

  public Student(Name name) => Name = name;

  public bool Equals(Student other)
  {
    if (ReferenceEquals(this, other))
      return true;
    if (ReferenceEquals(other, null))
      return false;

    return Name == (other.Name);
  }
}

public class Name : IEquatable<Name>
{
  public string First { get; }

  public Name(string first) => First = first;

  public bool Equals(Name other)
  {
    if (ReferenceEquals(this, other))
      return true;
    if (ReferenceEquals(other, null))
      return false;

    return First == other.First;
  }
}
var s1 = new Student(new Name("A"));
var s2 = new Student(new Name("A"));

Console.WriteLine(s1.Equals(s2).ToString());

当然,以这种方式进行相等性检查将返回 true。

var s1 = new Student(new Name("A"));
var s2 = s1;

Console.WriteLine(s1.Equals(s2).ToString());

你能告诉我我做错了什么吗?

C# IEquatable

评论

1赞 JL0PD 7/11/2022
您应该使用代替 .EqualityComparer 尝试为给定的类找到最佳相等方法,而如果它没有被覆盖,则仅通过引用进行比较System.Collections.Generic.EqualityComparer<T>.Default.Equals(o1, o2)====
0赞 Etienne de Martel 7/11/2022
@JL0PD “最佳相等方法”总是 ,所以需要抽出默认的相等比较器,直接调用该方法即可。Equals()
0赞 JL0PD 7/11/2022
@EtiennedeMartel,equals 的重载取决于类型是否实现 。如果 type 实现了接口,则检查将使用 .如果 type 未实现接口,则使用。所以它不是“总是相等的”IEquatableIEquatable<T>.Equals(T other)Object.Equals(object other)
0赞 Lokanath 7/11/2022
您可以使用 C# 记录,它们要简单得多,并且带有相等比较器

答:

3赞 Etienne de Martel 7/11/2022 #1

因此,默认情况下,引用类型仅比较引用。实现不会自动重载,您必须自己完成。 会重载该运算符,因此它在 中起作用,但您的类不起作用,因此在 中,使用默认行为,这相当于 。==IEquatable<T>==stringNameNameStudentReferenceEquals()

正确实现还意味着您需要覆盖 和 ,而这里没有这样做。IEquatable<T>Equals(object)GetHashCode()

2赞 Yong Shun 7/11/2022 #2

解决方案 1(推荐)

由于您已经实现了类的接口,因此只需在类中调用即可。IEquatableName.Equals()Student

public class Student : IEquatable<Student>
{
    public Name Name { get; }

    public Student(Name name) => Name = name;
    public bool Equals(Student other)
    {
        if (ReferenceEquals(this, other))
            return true;
        if (ReferenceEquals(other, null))
            return false;
        return Name.Equals(other.Name); // Replaces with .Equals
    }
}

示例 .NET Fiddle(解决方案 1)Sample .NET Fiddle (Solution 1)


解决方案 2

或者,您需要为 and 运算符实现运算符重载==!=

如果在以下位置使用运算符:==

public class Student : IEquatable<Student>
{
    ...

    public bool Equals(Student other)
    {
        ...

        return Name == (other.Name);
    }
}
public class Name : IEquatable<Name>
{
    ...
    
    public static bool operator == (Name a, Name b)
    {
        return a.First == b.First;
    }
    
    public static bool operator != (Name a, Name b)
    {
        return a.First != b.First;
    }
}

示例 .NET Fiddle(解决方案 2)Sample .NET Fiddle (Solution 2)