1、引言

  首先我们先来看看IEquatable<T>接口的出现解决了什么问题。

  我们知道,Object基类的Equals方法存在两个明显的问题。一是缺乏类型安全性,二是对于值类型而言需要装箱。在本文中我们就来看下IEquatable<T> Interface是如何解决这两个问题的。

2、IEquatable<T>接口

  我们都知道的一个事实是:如果想让Object的Equals方法为所有派生类型所用,那么,它的参数就必须设计成object类型。

  object是引用类型,这就意味着,如果传递一个值类型的参数,那么该参数将被装箱,这就会造成性能损失。

  另外,还存在另一个问题:将object类型设为参数还意味着类型安全性的缺失。

  解决装箱和类型安全性问题的一个办法就是定义一个新的Equals方法,该方法接受一个和待比较类型相同类型的参数。例如,对于字符串类型而言,定义一个接受string类型的Equals方法就能圆满解决这两个问题。

  但这会面临另一个新的问题,那就是:定义强类型的方法和OOP中的继承存在根本的冲突。我们不能在Object基类中定义一个强类型的Equals方法,因为Object基类根本无法知晓派生类的类型。

  那么,我们怎么样才能定义一个强类型的Equals方法,同时该方法能被所有类型使用呢?微软解决这个问题的思路就是通过提供一个IEquatable<T>接口,该接口向所有类型暴露。查看该接口的定义时,可以发现它仅暴露了一个Equals方法,如下所示。

using System;

namespace System
{
public interface IEquatable<T>
{
bool Equals(T other);
}
}

  该Equals方法和Object基类的虚Equals方法的作用相同,只不过它接受一个T类型参数,因此,它是强类型的,这意味着对于值类型而言,不存在装箱的问题。

3、IEquatable<T>接口和值类型

  我们可以通过一个简单的例子来证明IEquatable<T>接口的使用。

static void Main(String[] args)
{
int number1 = 1;
int number2 = 2;
int number3 = 1; Console.WriteLine(number1.Equals(number2));
Console.WriteLine(number1.Equals(number3)); }

  在上面的例子中,我们定义了三个整型变量,然后使用Equals方法进行比较。在VS中借助智能感知,可以发现对于int类型而言存在两个Equals方法,一个接受object参数,另一个接受int类型参数。接受int参数的Equals方法实现了IEquatable<T>接口,其中,T为int类型。因为我们在调用Equals方法时传递的是一个int类型变量,而不是一个object变量,因此,编译器将选择实现了IEquatable<T>接口的Equals方法。

  在平常开发中对于int类型的比较,我们不会像上面那样使用Equals方法进行比较,而是使用更加简便明了的==操作符。

  所有的基元类型都提供了对IEquatable<T>接口的实现,就像上面代码中的int类型那样,int类型实现了IEquatable<int>。

  总体而言,IEquatable<T>接口对值类型非常有用。但微软并没有为FCL中的非基元的值类型实现该接口,因此,不能寄希望于对FCL中值类型而言总是可以使用该接口。

4、IEquatable<T>和引用类型

  对于引用类型而言,IEquatable<T>接口并没有那么有用。一是因为引用类型不存在像值类型那样的由装箱导致的性能问题,二是因为IEquatable<T>接口不能很好地处理继承问题。

  但值的注意的是,String类型实现了IEquatable<T>接口,如下面所示

static void Main(String[] args)
{
string s1 = "Hello World";
string s2 = string.Copy(s1); Console.WriteLine(s1.Equals(s2); }  

  上面的代码中,C#编译器将直接选择强类型的Equals方法。另外,String类型是sealed的,因此,你不能从它继承。这样,在相等性判定和继承之间的冲突就不存在了。

  很明显,若一个类型定义了两个Equals方法,我们希望它们对相同的输入,产生相同的输出。关于这一点,微软提供的默认实现都严格履行了这一点。当我们自己去实现IEquatable<T>接口时,也要保证这一点。否则,别的开发者使用你定义的类型时将感到困惑。

浅析C#中的IEquatable<T>接口的更多相关文章

  1. 浅析JS中的模块规范(CommonJS,AMD,CMD)////////////////////////zzzzzz

    浅析JS中的模块规范(CommonJS,AMD,CMD)   如果你听过js模块化这个东西,那么你就应该听过或CommonJS或AMD甚至是CMD这些规范咯,我也听过,但之前也真的是听听而已.     ...

  2. 浅析c#中==操作符和equals方法

    在之前的文章中,我们讲到了使用C#中提供的Object类的虚Equals方法来判断Equality,但实际上它还提供了另外一种判断Equality的方法,那就是使用==运算符.许多童鞋也许会想当然的认 ...

  3. 浅析JDK中ServiceLoader的源码

    前提 紧接着上一篇<通过源码浅析JDK中的资源加载>,ServiceLoader是SPI(Service Provider Interface)中的服务类加载的核心类,也就是,这篇文章先介 ...

  4. 通过源码浅析Java中的资源加载

    前提 最近在做一个基础组件项目刚好需要用到JDK中的资源加载,这里说到的资源包括类文件和其他静态资源,刚好需要重新补充一下类加载器和资源加载的相关知识,整理成一篇文章. 理解类的工作原理 这一节主要分 ...

  5. 浅析Java中的深拷贝和浅拷

      浅析Java中的深拷贝和浅拷贝 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: in ...

  6. 浅析Java中的native关键字

    浅析Java中的native关键字 native关键字说明其修饰的方法是一个原生态方法,方法对应的实现不是在当前文件,而是在用其他语言(如C和C++)实现的文件中.Java语言本身不能对操作系统底层进 ...

  7. c# 把一个匿名对象赋值给一个Object类型的变量后,怎么取这个变量? c# dynamic动态类型和匿名类 详解C# 匿名对象(匿名类型)、var、动态类型 dynamic 深入浅析C#中的var和dynamic

    比如有一个匿名对象,var  result =......Select( a=>new {  id=a.id, name=a.name});然后Object  obj =  result ;我怎 ...

  8. 浅析 Linux 中的时间编程和实现原理一—— Linux 应用层的时间编程【转】

    本文转载自:http://www.cnblogs.com/qingchen1984/p/7007631.html 本篇文章主要介绍了"浅析 Linux 中的时间编程和实现原理一—— Linu ...

  9. 深入浅析python中的多进程、多线程、协程

    深入浅析python中的多进程.多线程.协程 我们都知道计算机是由硬件和软件组成的.硬件中的CPU是计算机的核心,它承担计算机的所有任务. 操作系统是运行在硬件之上的软件,是计算机的管理者,它负责资源 ...

随机推荐

  1. python logging 重复写日志问题

    用Python的logging模块记录日志时,遇到了重复记录日志的问题,第一条记录写一次,第二条记录写两次,第三条记录写三次...很头疼,这样记日志可不行.网上搜索到了原因与解决方案: 原因:没有移除 ...

  2. nginx收到空包问题

    tcpdump有收包,但是nginx的access.log显示post数据为空 可以通过tcpdump监控端口 http://www.cnblogs.com/linn/p/4792468.html 修 ...

  3. uwsgi的使用

    uwsgi是一个WEB服务器,只要用于python部分,类似于nginx ,apache 1 使用pip命令安装 pip install uwsgi 安装成功以后 可以做一个简单的测试 2 新建一个t ...

  4. Linux下安装MATLAB

    Why do I see "Preparing installation files ... Installing ... Finished..." in the terminal ...

  5. Vim插件之ale,LeaderF,completor.vim(win10)配置

    内容包含 vim-plug,异步插件管理,总之就是下起来快. ale,异步语法检查 LeaderF,快速查找文件 completor.vim vim8的快速补全 markdown预览 common s ...

  6. python的多线程编程之锁

    1. 背景概述 在上篇文章中,主要讲述了python中的socket编程的一些基本方面,但是缺少关于锁的相关概念,从而在这篇文章中进行补充. 由于在python中,存在了GIL,也就是全局解释器锁,从 ...

  7. 在线OFFICE方案

    Office在线预览及PDF在线预览的实现方式大集合 在线浏览office 文件 在线预览文档openoffice+swfTool 类百度文库文档上传.转换和展示功能项目开源代码 微软的office ...

  8. java 在MySQL中存储文件,读取文件(包括图片,word文档,excel表格,ppt,zip文件等)

    转自:https://blog.csdn.net/u014475796/article/details/49893261 在设计到数据库的开发中,难免要将图片或文档文件(如word)插入到数据库中的情 ...

  9. Notepad++中的高级查找

      准备以下字符串用来演示 abcdeab cdeabcde abcd eabcde   基于扩展的查找 基于扩展的查找不能算是真正的正则表达式搜索,因此这种查找方式仅是提供了支持转义字符.主要常用的 ...

  10. linux 使用systemctl 启动服务报错: Error: No space left on device

    By default, Linux only allocates 8192 watches for inotify, which is ridiculously low. And when it ru ...