未调用 C#GetHashCode/Equals 覆盖

Posted

技术标签:

【中文标题】未调用 C#GetHashCode/Equals 覆盖【英文标题】:C# GetHashCode/Equals override not called 【发布时间】:2010-11-06 22:42:14 【问题描述】:

我遇到了 GetHashCode 和 Equals 的问题,我已经为一个类覆盖了这些问题。我正在使用运算符 == 来验证两者是否相等,如果它们的哈希码相同,我希望这将调用 GetHashCode 和 Equals 以验证它们确实相等。

但令我惊讶的是,两者都没有被调用并且相等测试的结果是错误的(虽然它实际上应该是真的)。​​

覆盖代码:

    public class User : ActiveRecordBase<User>

        [...]

        public override int GetHashCode()
        
            return Id;
        

        public override bool Equals(object obj)
        
            User user = (User)obj;
            if (user == null)
            
                return false;
            

            return user.Id == Id;
        
    

平等检查:

    if (x == y) // x and y are both of the same User class
    // I'd expect this test to call both GetHashCode and Equals

【问题讨论】:

如果== 确实调用了您的Equals 方法,那么它会导致堆栈溢出,因为它在对象上使用== 运算符... 您显示的代码中没有任何内容表明需要调用 GetHashCode()。仅当您将对象用作集合的键时才会调用它。 【参考方案1】:

运营商==.GetHashCode().Equals() 完全分离。

您可能对 Microsoft Guidelines for Overloading Equals() and Operator == 感兴趣。

简短的版本是:使用.Equals() 实现平等比较。使用运算符 == 进行 identity 比较,或者如果您正在创建不可变类型(其中每个相等的实例都可以被认为是有效相同的)。此外,.Equals() 是一个虚方法,可以被子类覆盖,但运算符 == 取决于使用它的表达式的编译时类型。

最后,为了保持一致,在您实施.Equals() 的任何时候实施.GetHashCode()。重载运算符 != 任何时候重载运算符 ==

【讨论】:

我的对象是可变的。我预计调用 == 运算符实际上会调用 Equals 方法,我以前见过该方法,但我不明白为什么它现在不起作用,而它以前起作用...... @tomzx:== 运算符永远不会调用 .Equals() 方法,除非您重载它这样做。 @Daniel 您对“==”的建议不正确。微软一贯表示,如果要进行 IDENTITY 比较,则必须使用“ReferenceEquals”。例如,考虑字符串。如果您使用字符串生成器生成两个具有相同 CONTENTS 但不同 ADDRESSES 的字符串,则“==”将返回 TRUE(相等比较),但 ReferenceEquals 将返回 FALSE。 "==" 通常被认为是一个 EQUALITY 比较,并且通常被实现为执行一个类的 EQUALS 所做的任何事情。 简单测试:ReferenceEquals(new String("abc"), new String("abc")) 返回 false。但是 ((new String("abc")) == (new String("abc"))) 返回 true。 THEREFORE "==" 是 EQUALITY 比较,而不是 IDENTITY 比较。碰巧的情况是,如果一个类没有指定“==”做什么,则默认行为是使用 ReferenceEquals。还要考虑 VALUE 对象,它显然对“==”进行了相等性测试。 @ToolmakerSteve:来自我回答中的链接:“当类型不可变时,即实例中包含的数据无法更改,重载运算符 == 来比较值相等而不是引用相等可能很有用,因为作为不可变对象,只要它们具有相同的值,它们就可以被认为是相同的。在非不可变类型中覆盖 operator == 不是一个好主意。 -- 这对我来说意味着 == 应该只在相等和身份可以安全混合的地方表现得像一个相等运算符(即,与不可变的值类型类似的值)。【参考方案2】:

也许在你的User 类中再添加一个方法。

    public virtual bool Equals(User other) 
    
        if (ReferenceEquals(null, other)) return false;
        if (ReferenceEquals(this, other)) return true;
        return other.Id == Id;
    

【讨论】:

你不是说override 而不是virtual 吗?

以上是关于未调用 C#GetHashCode/Equals 覆盖的主要内容,如果未能解决你的问题,请参考以下文章

C函数中如何调用未实例化类的成员函数

未调用 didEnterRegion 但在目标 C 中调用了 didExitRegion

致命错误:未捕获的错误:调用 C:\xampp\htdocs\ 中未定义的函数 mysql_connect()

在 CMake 项目中从 C++ 调用 C 代码。未定义的符号。有外部 C

C ++线程未加入“没有活动异常的终止调用”

通过 Objective C 调用时未命中 Web 服务方法