当前位置: 首页 > article >正文

C# 相等性检测方法差异分析(==,Equals,ReferenceEquals)

先给结论:

对于每种类型创建2个一样的数据,比较结果如下表所示:

数据类型==EqualsReferenceEquals
int(值类型)×
引用类型×××
引用类型(带override)以operator ==实现为准以Equals覆写为准×
struct必须实现==操作符×
struct(带override)以operator ==实现为准以Equals覆写为准×
string×

一.比较操作符==

对于==的相等性检测,思路如下:

  1. 如果是struct,且没实现==操作符,则编译报错:
    在这里插入图片描述
  2. 如果实现了 == 操作符,则以 == 操作为准
  3. 如果是系统基础值类型,则可以直接判断值是否相等
  4. 如果是引用类型,则比较它们的引用是否相等,也就是栈上的保存的地址
public void Case1()
{
    TestClass testClass1 = new TestClass();
    TestClass testClass2 = new TestClass();

    Console.WriteLine($"testClass2 == testClass1 :{testClass2 == testClass1}");	 //输出: false
}
  1. 如果是string,因为string实现了==操作符,实际比较的是stirng内保存的内容是否相等
    这里可以看到C#对于 == 与Equals的实现,其实比较的实际存储的数据
public static bool operator == (String a, String b) {
	return String.Equals(a, b);
}

public static bool Equals(String a, String b) {
    if ((Object)a==(Object)b) {
        return true;
    }

    if ((Object)a==null || (Object)b==null) {
        return false;
    }

    if (a.Length != b.Length)
        return false;

    return EqualsHelper(a, b);
}

private unsafe static bool EqualsHelper(String strA, String strB)
{
    Contract.Requires(strA != null);
    Contract.Requires(strB != null);
    Contract.Requires(strA.Length == strB.Length);

    int length = strA.Length;

    fixed (char* ap = &strA.m_firstChar) fixed (char* bp = &strB.m_firstChar)
    {
        char* a = ap;
        char* b = bp;

        // unroll the loop
#if AMD64
        // for AMD64 bit platform we unroll by 12 and
        // check 3 qword at a time. This is less code
        // than the 32 bit case and is shorter
        // pathlength

        while (length >= 12)
        {
            if (*(long*)a     != *(long*)b) return false;
            if (*(long*)(a+4) != *(long*)(b+4)) return false;
            if (*(long*)(a+8) != *(long*)(b+8)) return false;
            a += 12; b += 12; length -= 12;
        }
#else
        while (length >= 10)
        {
            if (*(int*)a != *(int*)b) return false;
            if (*(int*)(a+2) != *(int*)(b+2)) return false;
            if (*(int*)(a+4) != *(int*)(b+4)) return false;
            if (*(int*)(a+6) != *(int*)(b+6)) return false;
            if (*(int*)(a+8) != *(int*)(b+8)) return false;
            a += 10; b += 10; length -= 10;
        }
#endif

        // This depends on the fact that the String objects are
        // always zero terminated and that the terminating zero is not included
        // in the length. For odd string sizes, the last compare will include
        // the zero terminator.
        while (length > 0) 
        {
            if (*(int*)a != *(int*)b) break;
            a += 2; b += 2; length -= 2;
        }

        return (length <= 0);
    }
}

二. Equals方法

在C#中,Equals是一个虚拟方法,它用于比较对象的内容是否相等。Equals方法是从System.Object基类继承而来,因此所有的C#类型都继承了Equals方法,但是默认情况下,对于引用类型而言,Equals方法只比较它们的引用是否相等,而不比较对象的内容。

  1. 覆写了Equals方法:以方法实现为准
  2. 基础值类型,struct:默认比较栈上存储的值是否相等
public void Case2()
 {
     TestStruct testStruct1 = new TestStruct()
     {
         _int = 10,
         _bool = false,
     };
     TestStruct testStruct2 = new TestStruct()
     {
         _int = 10,
         _bool = false,
     };
     Console.WriteLine($"testStruct1.Equals(testStruct2) :{testStruct1.Equals(testStruct2)}");	//输出: true
 }
  1. 引用类型:如果对象引用一致(栈内容),则相等
public void Case1()
{
    TestClass testClass1 = new TestClass();
    TestClass testClass2 = new TestClass();

    Console.WriteLine($"testClass2.Equals(testClass1) :{testClass2.Equals(testClass1)}");
}
  1. string类型:跟==实现一样,都覆写了Equals方法,比较的是实际内容

三.ReferenceEquals方法

在C#中,ReferenceEquals是一个静态方法,用于确定两个引用变量是否引用同一个对象(即两个引用是否指向同一内存地址)。ReferenceEquals方法是在System.Object类中定义的

  1. 对于值类型,默认会将值类型先装箱,转换成Object类型,这相当于创建了2个新对象,肯定不相等
 public void Case3()
 {
     int int1 = 10;
     int int2 = 10;
     Console.WriteLine($"ReferenceEquals(int1, int2) :{ReferenceEquals(int1, int2)}");  //输出: false
 }

在这里插入图片描述

  1. 对于string引用类型,则,直接比较的是引用(栈上保存)是否一致
public void Case5()
{
    string str1 = "Hello";
    string str2 = "Hello";
    Console.WriteLine(ReferenceEquals(str1, str2));  // 输出: false
    
    string str3 = str1;
    Console.WriteLine(ReferenceEquals(str1, str3));  // 输出: true
}

使用方法

  1. 对于系统内置值类型:直接使用==即可,也可以使用Equals,但是不能使用ReferenceEquals(装箱GC,且不能判断相等)
  2. 对于结构体:建议自定义实现操作符==,且覆写Equals方法
  3. 对于引用类型:如果只需要判断引用相当,都可以使用,但是如果要判断数据内保存的内容相等,则需要自己实现操作符==,且覆写Equals方法
  4. 对于string:默认全部都是比较的内容相等性

http://www.kler.cn/a/329170.html

相关文章:

  • Vue3中使用Axios构建高效的请求处理机制
  • 什么是 C++ 中的友元函数和友元类?友元的作用是什么?有什么注意事项?
  • 理解 Python 中的 __getitem__ 方法:在自定义类中启用索引和切片操作
  • 学习大数据DAY61 宽表加工
  • arkUI:网格布局(Grid)
  • 深入理解Go语言并发编程:从基础到实践
  • Kafka和RabbitMQ比较
  • LSTM模型实现光伏发电功率的预测
  • 滚雪球学MySQL[2.2讲]:基本数据操作详解:插入、查询、更新与删除
  • Linux 线程同步
  • 影院管理革新:小徐的Spring Boot应用
  • java 选择排序
  • 【易社保-注册安全分析报告】
  • 【中间件】fastDFS的相关知识
  • oracle解决关联查询报invalid number问题
  • 鸿蒙NEXT开发-组件事件监听和状态管理(基于最新api12稳定版)
  • calibre-web默认左上角字体修改
  • 【分布式微服务云原生】有哪些流行的微服务架构以及各自的组件,怎么完成服务治理等。
  • Spring MVC 常用注解
  • 深度学习自编码器 - 分布式表示篇
  • 鸿蒙开发(NEXT/API 12)【状态查询与订阅】手机侧应用开发
  • 《算法岗面试宝典》重磅发布!
  • Java之方法的使用
  • 《OpenCV》—— 指纹验证
  • DAY18||530.二叉搜索树的最小绝对值差 |501.二叉搜索树中的众数| 236.二叉树的最近公共祖先
  • 车辆重识别(2021ICML改进的去噪扩散概率模型)论文阅读2024/9/29