`
无恨星晨
  • 浏览: 31759 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
文章分类
社区版块
存档分类
最新评论

C#初学者对Equals方法的几个常见误解

阅读更多
很多C#的教材都会强调对象相等的概念。我们都知道,在C#的世界里存在两种等同性。一种是逻辑等同性:如果两个对象在逻辑上代表同样的值,则称他们具有逻辑等同性。另一种是引用等同性:如果两个引用指向同一个对象实例,则称他们具有引用等同性。

众所周知,Object类型有一个名为Equals的实例方法可以用来确定两个对象是否相等。Object的Equals的默认实现比较的是两个对象的引用等同性。而Object的派生类ValueTpye重写了Equals方法,它比较的是两个对象的逻辑等同性。也就是说,在C#里,引用类型的默认Equals版本关注的是引用等同性,而值类型关注的是逻辑等同性。当然,这并不总能满足我们的要求。所以每当我们更在意引用类型的逻辑等同性的时候,我们就应该重写Equals方法。

重写引用类型的Equals方法以改变其默认的比较方式的一个著名例子是String类。当我们写出“string1.Equals(string2)”这样的代码时,我们比较的不是string1和string2这两个引用所指向的是否为同一个实例(引用等同性),而是比较string1与string2所包含的字符序列是否相同(逻辑等同性)。

误解一:Equals方法和operator==具有相同的默认行为。

对于引用类型,如果没有为它重载==操作符,且其父类型也没有重写Equals方法,则这个引用类型Equals方法和operator==具有相同的默认行为,即它们比较的都是对象的引用等同性。然而对于值类型来说,就完全不是这么回事了!因为如果你没有为自定义值类型重载operator==的话,就不能写这样的代码“myStruct1 == myStruct2”,否则会得到一个编译错误,原因是值类型没有相等操作符重载的默认实现。

误解二:自定义类的Equals的方法默认实现将自动调用operator==方法,或operator==方法的默认实现将自动调用Equals方法。

经常听到有人说某某类型是引用类型,所以它的Equals方法的默认实现将自动调用operator==方法。这种说法完全是没有道理的。正如上文所说的,引用类型Equals方法的默认实现来自Object,而值类型的默认实现来自TypeValue,就算他们会使用==操作符,使用的也是Object或TypeValue的重载版本。原则上来说,只要我们没有重写一个类的Equals方法,那么它就会继承其父类的实现,而父类是没有机会使用子类型的操作符重载的。同样,只要我们没有在一个类的==操作符重载中调用Equals方法,它是不会自动调用的。

误解三:值类型的默认Equals实现是对两个对象进行逐位比较的。

有些人认为值类型的Equals默认实现就是通过比较两个对象在内存中的位表示,即如果所有的二进制位都相等,则说明这两个对象“等同”。这是不准确的。因为其实值类型的Equals默认实现是对值类型的每个字段都调用该字段类型的Equals方法,如果所有字段的Equals方法都返回true,则他们才可能相等。来看一个例子:

    class MyClass
    {
        public override bool Equals(object obj)
        {
            Console.WriteLine("MyClass的Equals方法被调用了。");
            return true;
        }
    }

    struct MyStruct
    {
        public MyClass Filed;
    }

    class Program
    {
        static void Main(string[] args)
        {
            MyStruct a;
            MyStruct b;
            a.Filed = new MyClass();
            b.Filed = new MyClass();
            Console.WriteLine(a.Equals(b));
        }
    }


很显然,a和b拥有完全不同的二进制位表示。但是最终打印的结果是: MyClass的Equals方法被调用了。
 
True


这说明值类型的默认实现是通过调用字段的Equals方法来确定两个对象是否相等,而不是通过比较他们的二进制位是否一致来确定的。

误解四:Equals是非常基本、非常常用的方法,所以其默认的实现不存在性能问题。

对于引用类型,Equals的默认实现很简单,仅仅需要判断两个引用是不是同一种类型、两个引用指向的是不是同一块内存就可以了。所以其性能也没有问题。但是对于值类型,Equals的任务就没有这么简单了。它需要对两个对象的所有字段都做出比较,即逐字段调用字段类型的Equals。由于在ValueType(值类型Equals方法默认实现的位置)中,不可能知道它所有的子类型都包含哪些字段,所以为了调用子类型字段的Equals方法,ValueType的Equals就需要使用反射技术。您可能已经看出来了,反射并不是一种性能友好的技术,所以值类型的Equals方法算不上高效。这也正是为什么微软推荐我们为自定义值类型重写Equals方法的原因。
分享到:
评论

相关推荐

    C#中Equals方法的常见误解

    然而,初学者往往对这个方法存在一些常见的误解。以下是对这些误解的详细解释: 误解一:`Equals`方法和`operator==`具有相同的默认行为。 实际上,对于引用类型,如果未重载`==`运算符并且父类型也未重写`Equals`...

    C#使用Equals()方法比较两个对象是否相等的方法

    在C#编程语言中,`Equals()`方法是一个用于比较对象是否相等的关键工具。这个方法在处理对象间的等价性判断时非常常见,特别是在需要确定两个变量或实例是否表示相同数据的情况下。`Equals()`方法是Object类的一个...

    C# Equals 和 GetHashCode 方法重写

    ### C# Equals 和 GetHashCode 方法重写 在C#编程中,`Equals` 和 `GetHashCode` 方法是非常重要的成员方法,它们对于确保对象的正确比较以及高效地存储和检索对象至关重要。这两个方法通常需要在自定义类中进行...

    C#初学者登陆的例子

    这个“C#初学者登录例子”旨在为初学者提供基础的登录功能实现,涵盖了一些核心概念和技术。以下是对这些知识点的详细说明: 1. **基础语法与控件**:C#是一种类型安全、面向对象的语言,它的语法简洁且强大。在这...

    重写equals方法

    在 Java 中,equals 方法是一个非常重要的方法,它用于判断两个对象是否相等,而不是判断两个对象的引用是否相同。在 Object 基类中,equals 方法的实现是使用“==”操作符来比较对象的引用,但是这并不满足实际需求...

    C#字符串常用方法和实例,适合初学者

    本文将深入探讨C#中字符串的常用方法及其应用示例,特别适合初学者掌握基础的字符串操作技巧。 ### 字符串不可变性 C#中的字符串具有一个核心特性——不可变性。这意味着一旦一个字符串被创建,其内容不能被直接...

    重载equals方法示例

    重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例重载equals方法示例

    equals方法的重写.docx

    `equals`方法是Java语言中Object类的一个重要成员方法,其默认实现是比较两个对象的内存地址是否相同(即是否为同一个对象)。为了使对象之间能够基于内容进行比较,通常需要在具体的类中重写`equals`方法。 #### ...

    Java中equals方法隐藏的陷阱

    - **返回类型错误**:另一个常见的错误是将`equals`方法的返回类型设置为`void`或其他非布尔类型的值。这显然违反了`equals`方法的设计意图,即返回一个表示相等性的布尔值。 **解决方案**: 始终遵循标准的`equals...

    set接口经常用的hashCode和equals方法详解

    在这个例子中,`equals`方法根据`name`和`age`属性来判断两个`Person`对象是否相等,而`hashCode`方法也综合考虑了这两个属性,以确保`equals`方法返回`true`的对象具有相同的哈希码。 #### 七、总结 在Java中,...

    hashcode和equals方法

    equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.

    js equals方法

    综上所述,`equals`方法是JavaScript中实现深度比较的常见做法,它弥补了内置等于操作符在复杂数据结构比较上的不足,使得我们能够更精确地判断两个对象是否相等。在实际开发中,根据项目需求,可以灵活调整和优化这...

    重写toString和equals方法

    在 Java 中,每个对象都继承自 Object 类,而 Object 类中定义了两个重要的方法:toString() 和 equals()。这两个方法都是非常重要的,它们分别用于对象的字符串表示和对象比较。然而,在大多数情况下,我们需要重写...

    java中的==和equals()方法1

    下面将详细解释这两个方法的工作原理、使用场景以及一些常见误区。 首先,`==`运算符主要用于比较基本类型的变量和引用类型的变量。对于基本类型(如int, double, char等),`==`直接比较它们的值是否相等。例如: ...

    C#常见控件的使用

    这些成员包括但不限于构造函数、 Dispose方法(用于释放资源)、Equals方法(比较两个控件是否相等)、Focus方法(设置焦点)、GetContainerControl方法(获取容器控件)、各种Raise方法(引发特定事件)以及刷新和...

    ==和equals的比较

    `equals` 方法是 C# 中的对象比较方法,它用于比较两个对象的值是否相同,而不是比较引用是否相同。例如: ```csharp string a = "hello"; string b = new string(new char[] { 'h', 'e', 'l', 'l', 'o' }); bool ...

    C#查找列表中所有重复出现元素的方法

    在C#编程中,处理列表数据结构是常见的任务之一,特别是在需要查找并处理重复元素的场景下。本篇文章将深入探讨如何在C#中查找列表中的所有重复元素,并提供一个具体的实现示例。 首先,我们需要了解C#中的列表类型...

    C#中Equals和GetHashCode使用及区别

    C#中的Equals和GetHashCode是两个非常重要的方法,它们在对象比较和哈希表中扮演着关键角色。今天,我们将详细介绍这两个方法的使用和区别。 Equals方法是用于比较两个对象是否相等的方法。它是Object类中的一个...

Global site tag (gtag.js) - Google Analytics