c# - 等于实现并覆盖 Equals、IEquatable、== 和 !=

标签 c# equals

我看到很多关于 C# 中的相等性以及如何实现它的帖子和问题。我想尝试收集最佳实践,并提供一个或多或少没有样板代码、不重复代码的解决方案。

从这样一个简单的类开始:

public class Foo
{
    public int Bar { get; set; }
}

我现在想向此类添加 Equals 的所有可能性调用首先使用 ReSharper 建议覆盖它:

public override bool Equals(object obj)
{
    if (ReferenceEquals(null, obj)) return false;
    if (ReferenceEquals(this, obj)) return true;
    if (obj.GetType() != GetType()) return false;

    if(obj is Foo foo)
    {
        // here all the values should be checked
        return Bar == foo.Bar;
    }

    return false;
}

现在我已经覆盖了 Equals 调用,但留下了 ==!=具有该建议的运营商 https://www.loganfranken.com/blog/698/overriding-equals-in-c-part-3/

public static bool operator ==(Foo a, 
                               Foo b)
{
    if(ReferenceEquals(null, a)) return false; 
            
    return a.Equals(b); 
}

public static bool operator !=(Foo a,
                               Foo b)
{
    return !(a == b);
}

现在的最后一步是实现 IEquatable<>像这样的界面并调整覆盖Equals像这样离开类:

public class Foo : IEquatable<Foo>
{
    public int Bar { get; set; }

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

        // here all the values should be checked
        return Bar == other.Bar;
    }

    public override bool Equals(object obj)
    {
        if (ReferenceEquals(null, obj)) return false;
        if (obj.GetType() != GetType()) return false;

        return Equals(obj as Foo);
    }

    public static bool operator ==(Foo a,
                                   Foo b)
    {
        if(ReferenceEquals(null, a)) return false;
        
        return a.Equals(b);
    }

    public static bool operator !=(Foo a,
                                   Foo b)
    {
        return !(a == b);
    }
}

现在,在我看来,我已经或多或少地删除了所有重复代码(不幸的是,我想不出一种方法来消除空检查)。我将在 Equals(Foo other) 中实现“核心逻辑”方法和其他方法可以复制到任何其他类。

这里有我遗漏的陷阱或问题吗?或者有什么关于获得更少代码的建议吗?我并不是想获得最佳性能,干净的代码应该是此实现和其他类的可重用性的主要标准。那么是否可以将最后 3 个方法毫无问题地复制到任何其他类并且仅实现 IEquatable<>当然,还要更改调用?

另请注意,我没有实现 GetHashCode()现在。

最佳答案

您不应该重复自己:实现 public bool Equals(Foo other) 就足够了; 所有其他:Equals==!= 可以从 Equals(Foo other) 派生:

public class Foo : IEquatable<Foo>
{
    public int Bar { get; set; }

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

        // here all the values should be checked
        return Bar == other.Bar;
    }

    // Here we can put it short 
    public override bool Equals(object obj) => obj is Foo other && Equals(other);

    //TODO: Don't forget about hash 
    // Here I put the easiest approach which exploits the fact we
    // have just one property of type int. 
    public override int GetHashCode() => Bar;

    // Note ReferenceEquals(a, b): we want null == null be true
    public static bool operator == (Foo a, Foo b) =>
      ReferenceEquals(a, b) || (a is not null && a.Equals(b));

    public static bool operator !=(Foo a, Foo b) => !(a == b);
}

关于c# - 等于实现并覆盖 Equals、IEquatable、== 和 !=,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67805459/

相关文章:

c# - 如何从可能为空的 SQL Server 中安全地读取字符串值?

c# - Azure.Search.Documents v11 中的 ContinuationToken 在哪里

c# - 为非托管程序集动态创建包装器?

Ruby 数组相等

java - 为 OR 逻辑计算 hashCode

java - 为大对象创建 .hashcode() 和 .equals() 方法

java - DoubleLinkedList 的 equals 方法

c# - 如何使用asp.net调用javascript函数?

c# - 从 C# 向 Java 应用程序 (Minecraft) 发送输入

c# - Equals() 方法在比较时无法识别相似/相同的字符