• 浅析C#中的IEquatable<T>接口


      

    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>接口时,也要保证这一点。否则,别的开发者使用你定义的类型时将感到困惑。

  • 相关阅读:
    为什么使用内部类?怎样使用内部类? 2016年12月15号
    java内部类 2016年12月13号
    接口与抽象类的区别与联系 2016年12月13日
    多态的向上转型和向下转型 2016.12.8
    构造器的调用顺序 2016.12.8
    static final 和final的区别 2016.12.07
    根据进程号查询占用资源多的线程
    Intellij idea启动项目提示"ClassNotFoundException"
    IntelliJ IDEA setup JDK无效
    (转)面试合集
  • 原文地址:https://www.cnblogs.com/lian--ying/p/9502879.html
Copyright © 2020-2023  润新知