百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 热门文章 > 正文

C#之System.Object类型的主要方法

bigegpt 2024-08-09 11:05 2 浏览

ReferenceEquals(object a, object b)

静态方法,判断两个引用类型对象是否指向同一个地址。即适用范围只能对于引用类型操作。对于任何两个值类型数据比较,即使是与自身比较都会返回False,因为调用这个方法时,值类型数据要进行装箱操作,转换为object类型,两次装箱,堆上会产生两个对象。


Console.WriteLine(ReferenceEquals(1, 1)); // Fals

这个方法可以用来验证字符串驻留,当字符串驻留时,不会产生新的字符串对象。

Console.WriteLine(ReferenceEquals("hello", "hello"));    // True

Equals(object a, object b)

静态方法。如果两个比较对象均为null或者ReferenceEquals(a, b)返回True,则返回True。

Equals(object o)

虚方法,实例方法,可以重写。调用结果和调用Equals(object a, object b)是一样的,即如果两个对象均为null或者具有相同的引用就返回True,否则返回False。

任何类型都可以重写这个方法。

对于引用类型,即使引用类型包含很多成员,使用Equals比较引用类型时,仅仅考虑两个对象是否具有相同的引用,而不是逐个成员进行比较。所以对于引用类型,除非有其他判等逻辑,否则也不需要重写该方法。

System.ValueType值类型重写了该方法,仅仅比较值是否相等。如果值类型包含很多成员,例如结构体,则使用反射,取得所有成员然后逐个进行比较。为了避免反射造成性能损失,必须重写这个方法,即只需要遍历所有结构的属性并一一进行比较即可。倘若只是需要部分属性相等即可,那就更应该重写了。

        struct Rectangle
        {
            double width { get; set; }
            double height { get; set; }

            public override bool Equals(object obj)
            {
                if (obj != null && obj is Rectangle)
                {
                    // 强转为Rectangle类型
                    Rectangle rect = (Rectangle)obj;
                    // 遍历所有属性
                    return (rect.width == width) && (rect.height == height);
                }
                return false;
            }
        }

虽然字符串是引用类型,但它重写了该方法,行为和值类型一样,仅仅比较值是否相等。这是字符串行为看起来和值类型差不多的一个原因。

如果重写了Equals,还应该重写GetHashCode方法,否则会有警告消息。这两个方法是有连带关系的,如果两个对象相等,那么他的哈希码必须也相等,不过反过来,两个对象不相等,哈希码也有可能相等。

==和上面判等方法的关系

==是运算符重载,如果两边都是引用类型,则等同于ReferenceEquals。但string是特例,如果两边都是字符串或者值类型,==比较值是否相等。但是==不能用于结构体,除非重载它。

        struct Rectangle
        {
            double Width { get; set; }
            double Height { get; set; }

            public Rectangle(double w, double h)
            {
                Width = w;
                Height = h;
            }

            public override bool Equals(object obj)
            {
                if (obj != null && obj is Rectangle)
                {
                    // 强转为Rectangle类型
                    Rectangle rect = (Rectangle)obj;
                    // 假如面积相等就算相等
                    return Width * Height == rect.Width * rect.Height;
                }
                return false;
            }
        }

此时

Rectangle rect1 = new Rectangle(1, 2);
Rectangle rect2 = new Rectangle(2, 1);
Console.WriteLine(ReferenceEquals(rect1, rect2));   // False
Console.WriteLine(rect1.Equals(rect2)); // True

如果没有重写Equals方法,则应该输出两个False,但是我们不能直接使用==判等。

Console.WriteLine(rect1==rect2);	// ×

我们必须重载它:

            public static bool operator ==(Rectangle rect1, Rectangle rect2)
            {
                return rect1.Equals(rect2);
            }
            public static bool operator !=(Rectangle rect1, Rectangle rect2)
            {
                return !rect1.Equals(rect2);
            }

此时,可以通过编译并输出正确的值。重载==时,也必须重载!=。

GetHashCode

CLR中,任何对象任何实例都对应一个哈希码。GetHashCode能获取任意对象的哈希码。相同的对象哈希码必然相同,所以重写Equals必须重写GetHashCode,保证两者有相同的语义。

重写GetHashCode除了保证相同对象哈希码必然相同之外,还要保证哈希码是不可变的,所以如果哈希码基于对象的一些成员,那成员也应该是不可变的。通常借助于类型的唯一识别成员,例如id等。

重写Equals完整版本:

1. 重写Equals覆盖Object.Equals

2. 重写GetHashCode

3. 重载等号不等号

4. 实现IEquatable<T>接口,使得值类型比较大小时不会被隐式装箱

    struct Rectangle : IEquatable<Rectangle>
    {
        double Width { get; set; }
        double Height { get; set; }

        public override bool Equals(object obj)
        {
            if (obj != null && obj is Rectangle)
            {
                // 强转为Rectangle类型
                Rectangle rect = (Rectangle)obj;
                // 遍历属性
                return (rect.Width == Width) && (rect.Height == Height);
            }
            return false;
        }

        /// <summary>
        /// 实现接口的方法,该方法会在传入参数为Rectangle时优先于Object.Equals方法
        /// 避免了装箱
        /// </summary>
        /// <param name="other"></param>
        /// <returns></returns>
        public bool Equals(Rectangle other)
        {
            return (other.Width == Width) && (other.Height == Height);
        }

        public override int GetHashCode()
        {
            // 保证语义一致
            return Width.GetHashCode() * Height.GetHashCode();
        }

        public static bool operator ==(Rectangle rect1, Rectangle rect2)
        {
            return rect1.Equals(rect2);
        }

        public static bool operator !=(Rectangle rect1, Rectangle rect2)
        {
            return !rect1.Equals(rect2);
        }
    }

ToString

虚方法,重写的可能性比较大,例如希望遍历对象的所有属性,然后打印。

GetType

返回对象指向的类型对象,返回值类型为System.Type。得到类型对象之后可以通过反射方式获得类型对象的成员,例如字段属性方法等。

Finalize

GC决定回收对象之后会调用这个方法,如果这时候要做一些额外的事,例如回收对象的非托管属性或对象,则应重写这个方法。

相关推荐

【Docker 新手入门指南】第十章:Dockerfile

Dockerfile是Docker镜像构建的核心配置文件,通过预定义的指令集实现镜像的自动化构建。以下从核心概念、指令详解、最佳实践三方面展开说明,帮助你系统掌握Dockerfile的使用逻...

Windows下最简单的ESP8266_ROTS_ESP-IDF环境搭建与腾讯云SDK编译

前言其实也没啥可说的,只是我感觉ESP-IDF对新手来说很不友好,很容易踩坑,尤其是对业余DIY爱好者搭建环境非常困难,即使有官方文档,或者网上的其他文档,但是还是很容易踩坑,多研究,记住两点就行了,...

python虚拟环境迁移(python虚拟环境conda)

主机A的虚拟环境向主机B迁移。前提条件:主机A和主机B已经安装了virtualenv1.主机A操作如下虚拟环境目录:venv进入虚拟环境:sourcevenv/bin/active(1)记录虚拟环...

Python爬虫进阶教程(二):线程、协程

简介线程线程也叫轻量级进程,它是一个基本的CPU执行单元,也是程序执行过程中的最小单元,由线程ID、程序计数器、寄存器集合和堆栈共同组成。线程的引入减小了程序并发执行时的开销,提高了操作系统的并发性能...

基于网络安全的Docker逃逸(docker)

如何判断当前机器是否为Docker容器环境Metasploit中的checkcontainer模块、(判断是否为虚拟机,checkvm模块)搭配学习教程1.检查根目录下是否存在.dockerenv文...

Python编程语言被纳入浙江高考,小学生都开始学了

今年9月份开始的新学期,浙江省三到九年级信息技术课将同步替换新教材。其中,新初二将新增Python编程课程内容。新高一信息技术编程语言由VB替换为Python,大数据、人工智能、程序设计与算法按照教材...

CentOS 7下安装Python 3.10的完整过程

1.安装相应的编译工具yum-ygroupinstall"Developmenttools"yum-yinstallzlib-develbzip2-develope...

如何在Ubuntu 20.04上部署Odoo 14

Odoo是世界上最受欢迎的多合一商务软件。它提供了一系列业务应用程序,包括CRM,网站,电子商务,计费,会计,制造,仓库,项目管理,库存等等,所有这些都无缝集成在一起。Odoo可以通过几种不同的方式进...

Ubuntu 系统安装 PyTorch 全流程指南

当前环境:Ubuntu22.04,显卡为GeForceRTX3080Ti1、下载显卡驱动驱动网站:https://www.nvidia.com/en-us/drivers/根据自己的显卡型号和...

spark+python环境搭建(python 环境搭建)

最近项目需要用到spark大数据相关技术,周末有空spark环境搭起来...目标spark,python运行环境部署在linux服务器个人通过vscode开发通过远程python解释器执行代码准备...

centos7.9安装最新python-3.11.1(centos安装python环境)

centos7.9安装最新python-3.11.1centos7.9默认安装的是python-2.7.5版本,安全扫描时会有很多漏洞,比如:Python命令注入漏洞(CVE-2015-2010...

Linux系统下,五大步骤安装Python

一、下载Python包网上教程大多是通过官方地址进行下载Python的,但由于国内网络环境问题,会导致下载很慢,所以这里建议通过国内镜像进行下载例如:淘宝镜像http://npm.taobao.or...

centos7上安装python3(centos7安装python3.7.2一键脚本)

centos7上默认安装的是python2,要使用python3则需要自行下载源码编译安装。1.安装依赖yum-ygroupinstall"Developmenttools"...

利用本地数据通过微调方式训练 本地DeepSeek-R1 蒸馏模型

网络上相应的教程基本都基于LLaMA-Factory进行,本文章主要顺着相应的教程一步步实现大模型的微调和训练。训练环境:可自行定义,mac、linux或者window之类的均可以,本文以ma...

【法器篇】天啦噜,库崩了没备份(天啦噜是什么意思?)

背景数据库没有做备份,一天突然由于断电或其他原因导致无法启动了,且设置了innodb_force_recovery=6都无法启动,里面的数据怎么才能恢复出来?本例采用解析建表语句+表空间传输的方式进行...