C# ==、Equals和ReferenceEquals

值类型

== : 比较两者的“内容”是否相同,即“值”是否一样
Equals:比较两者的“内容”是否相同,即“值”是否一样
ReferenceEquals:返回false,因为会对值类型进行装箱再进行比较

 

引用类型

== : 比较的是引用变量指向的对象在堆中的存储地址是否一样
Equals: 比较的是引用变量指向的对象在堆中的存储地址是否一样
ReferenceEquals: 比较的是引用变量指向的对象在堆中的存储地址是否一样

 

注意:对于String类型都是比较String的值是否一样

 

如果自定义的类型重写了Object的Equals方法,则也需要重写GetHashCode方法,如果重写了Equals但没有重写GetHashCode的话在以该自定义类型为键的哈希表中(如Dictionary和Hashtable)就会出问题(比如永远找不到指定key)

如下:

a) 定义重写了Equals但没有重写GetHashCode的自定义类型_20210304_2_Model

复制代码
    public class _20210304_2_Model
    {
        public int Age { get; set; }

        public override bool Equals(object obj)
        {
            var tempObj = obj as _20210304_2_Model; // 转换不成功返回null

            if (tempObj == null) return false;

            return this.Age == tempObj.Age;
        }
    }
复制代码

b) 测试代码如下

            Console.WriteLine("是否相等:"+(new _20210304_2_Model { Age = 10 }.Equals(new _20210304_2_Model { Age = 10 })));
            Dictionary<_20210304_2_Model, int> dics = new Dictionary<_20210304_2_Model, int>();
            dics.Add(new _20210304_2_Model { Age = 10 }, 10);
            var res = dics[new _20210304_2_Model { Age = 10 }]; // 报错找不到   

c) 运行结果

 

 d) 原因:对于Dictionary来说,虽然我们存储的时候是键值对,但是CLR会先把key转成HashCode并且验证Equals后再做存储(即当key的HashCode和Equals都不相等时才会存储新的键),根据key取值的时候也是把key转换成HashCode并且验证Equals后再取值(当Key的HashCode和Equals都相等时来取键值),一定要注意验证时HashCodeEquals的关系是并且(&&)的关系。也就是说,只要GetHashCodeEqulas中有一个方法没有重写,在验证时没有重写的那个方法会调用基类的默认实现,而这两个方法的默认实现都是根据内存地址判断的,也就是说,其实一个方法的返回值永远会是false。其结果就是,存储的时候你可能任性的存,在取值的时候就是你哭着找不着娘了。

在重写Object类的GetHashCode方法时也要注意:

如果两个对象比较相等(Equals返回true),则每个对象的GetHashCode方法必须返回相同的值。 但是,如果两个对象的比较不相等,则两个对象的GetHashCode方法不必返回不同的值。

比如如下重写:

复制代码
    public class _20210304_2_Model
    {
        public int Age { get; set; }

        public override bool Equals(object obj)
        {
            var tempObj = obj as _20210304_2_Model; // 转换不成功返回null

            if (tempObj == null) return false;

            return this.Age == tempObj.Age;
        }

        public override int GetHashCode()
        {
            return this.Age;
        }
    }
复制代码

测试代码:

        public void Run()
        {
            Console.WriteLine("是否相等:"+(new _20210304_2_Model { Age = 10 }.Equals(new _20210304_2_Model { Age = 10 })));
            Dictionary<_20210304_2_Model, int> dics = new Dictionary<_20210304_2_Model, int>();
            dics.Add(new _20210304_2_Model { Age = 10 }, 10);
            dics.Add(new _20210304_2_Model { Age = 10 }, 10); // 无法再添加了,因为key:new _20210304_2_Model { Age = 10 }的Equals和GetHashCode比较都一样
            var res = dics[new _20210304_2_Model { Age = 10 }];         
        }

运行结果:

 

 

参考文档:https://www.cnblogs.com/xiaochen-vip8/p/5506478.html

微软官方GetHashCode文档:https://docs.microsoft.com/ZH-CN/dotnet/api/system.object.gethashcode?view=netcore-3.1

 

对象和引用变量关系:https://www.cnblogs.com/zsupreme/p/13406227.html

.NET 中间语言示例解析:https://docs.microsoft.com/zh-tw/previous-versions/dd229210(v=msdn.10)

posted @   温故纳新  阅读(244)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)
点击右上角即可分享
微信分享提示