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 @ 2021-03-05 10:59  温故纳新  阅读(236)  评论(0编辑  收藏  举报