谨慎使用显式接口方法实现

原创 2017年06月12日 08:52:12

上一篇文章我们讲解了隐式和显式接口背后发生的故事(http://blog.csdn.net/u010533180/article/details/72954192),而且要慎用显式接口方法,本篇文章讲讲显式接口方法带来的一些问题。
显式接口方法 EIMI 最主要的问题如下:
1) 没有文档解释一个类型具体如何实现一个EIMI,也没有Microsof Visual Studio 智能感知支持。
2) 值类型的实例在转型为接口时需要进行装箱操作。
3) EIMI 方法不能由派生类型调用。
下面详细说说这些问题。
在.NET Framework 参考文档中查看一个类型的方法时,会列出显式接口方法实现(EIMI),单没有提供类型特有的帮助,只能看到接口方法的常规性帮助。例如:Int32类型的文档只是说它实现了IConvertible 接口的所有方法。但是开发人员不能直接在一个Int32上调用一个IConvertible 方法。例如,下面的代码无法编译:

  public static void Main()
        {
            Int32 x = 5;
            Single s = x.ToSingle(null);
         }

会报如下的错误:
这里写图片描述
错误 5 “int”不包含“ToSingle”的定义,并且找不到可接受类型为“int”的第一个参数的扩展方法“ToSingle”(是否缺少 using 指令或程序集引用?)

这里写图片描述

这里写图片描述

从上述各图中明显看出Int32类型没有定义ToSingle方法,单事实上这个方法已经定义了。
要想在一个Int32上调用ToSingle,首先必须先把这个Int32转型为IConvertible。

        public static void Main()
        {
            Int32 x = 5;
            Single s = ((IConvertible) x).ToSingle(null);
        }

这时还需要进行转型操作,将Int32值类型转型为IConvertible,还要对值类型进行装箱,这样既浪费内存,也损害性能。这是之前提到的第二个大问题。

我们看如下代码:

class Base : IComparable
    {

        #region IComparable 成员

        int IComparable.CompareTo(object obj)
        {
            Console.WriteLine("Base's CompareTo");
            return 0;
        }

        #endregion
    }
    class Derived : Base, IComparable
    {
        public int CompareTo(Object o)
        {
            Console.WriteLine("Derived's CompareTo");
            base.CompareTo(o);
            return 0;
        }
    }

上述代码出现如下错误:
错误 6 “NowCoderProgrammingProject.Base”并不包含“CompareTo”的定义
这里写图片描述

Base类没有提供一个可以调用的公共或受保护的CompareTo方法,它提供的是一个只能用IComparable类型的变量来调用CompareTo方法,可把上述代码修改为如下方法:

 class Base : IComparable
    {

        #region IComparable 成员

        int IComparable.CompareTo(object obj)
        {
            Console.WriteLine("Base's CompareTo");
            return 0;
        }

        #endregion
    }
    class Derived : Base
    {
        public int CompareTo(Object o)
        {
            Console.WriteLine("Derived's CompareTo");
            IComparable c = this;
            c.CompareTo(o);
            return 0;
        }
    }
      class EIMI
    {
        public static void Main()
        {
            Derived d= new Derived();
            object o= "";
            d.CompareTo(o);
        }        
    }

运行输出结果如下:

Derived's CompareTo
Base's CompareTo

上述代码之所以能够运行是因为在Dervied类中去掉了IComparable 接口的继承,通过转型为IComparable 然后调用对应的CompareTo方法。但是有时候,不能简单的将接口从类型中去除,因为希望派生类实现一个接口方法。解决这个问题的方法是在基类中除了提供一个被选为显式实现的接口方法,还要提供一个虚方法。然后Derived类可以重写虚方法。看如下代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NowCoderProgrammingProject
{
    class Base : IComparable
    {

        #region IComparable 成员
        /// <summary>
        /// 显示实现接口方法EIMI
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        int IComparable.CompareTo(object obj)
        {
            Console.WriteLine("Base's CompareTo");
            return VirtualCompareTo(obj);//调用虚方法
        }

        #endregion
        /// <summary>
        /// 用于派生类的虚方法
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        public virtual int VirtualCompareTo(object obj)
        {
            Console.WriteLine("Base's Virtual CompareTo");
            return 0;
        }
    }
    class Derived : Base,IComparable
    {
        /// <summary>
        /// 复写父类的方法,也是接口方法的实现
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        public override int VirtualCompareTo(Object o)
        {
            Console.WriteLine("Derived's CompareTo");
            return base.VirtualCompareTo(o);//调用父类的虚方法
        }
    }
    class EIMI
    {
        public static void Main()
        {
            Derived d= new Derived();
            object o= "";
            d.VirtualCompareTo(o);
        }        
    }
}

运行结果如下:

Derived's CompareTo
Base's Virtual CompareTo

注意前面将虚方法定义成公共方法,但有的情况下,可能需要定义为受保护的方法。把方法定义为受保护是可以的,但必须进行一些小改动。 通过上述代码的讨论清楚的证明了务必谨慎使用EIMI。许多开发人员就肆无忌惮的使用EIMI。千万不要这样做!EIMI在某些情况下确实有用,但是应该尽量避免使用,因为它们使类型的使用变的困难很多。
下面的例子是把EIMI更改受保护的方法,然后需要增加一个新的公共方法,因为受保护的方法只能在本类以及子类中才能调用:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace NowCoderProgrammingProject
{
    class Base : IComparable
    {

        #region IComparable 成员
        /// <summary>
        /// 显示实现接口方法EIMI
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        int IComparable.CompareTo(object obj)
        {
            Console.WriteLine("Base's CompareTo");
            return VirtualCompareTo(obj);//调用虚方法
        }

        #endregion
        /// <summary>
        /// 用于派生类的虚方法
        /// </summary>
        /// <param name="obj"></param>
        /// <returns></returns>
        protected virtual int VirtualCompareTo(object obj)
        {
            Console.WriteLine("Base's Virtual CompareTo");
            return 0;
        }
    }
    class Derived : Base,IComparable
    {
        /// <summary>
        /// 复写父类的方法,也是接口方法的实现
        /// </summary>
        /// <param name="o"></param>
        /// <returns></returns>
        protected override int VirtualCompareTo(Object o)
        {
            Console.WriteLine("Derived's CompareTo");
            return base.VirtualCompareTo(o);//调用父类的虚方法
        }

        public int ProtectedCompareTo(object o)
        {
            Console.WriteLine("Derived's Protected CompareTo");
            return VirtualCompareTo(o);//调用父类的虚方法
        }
    }
    class EIMI
    {
        public static void Main()
        {
            Derived d= new Derived();
            object o= "";
            d.ProtectedCompareTo(o);
        }        
    }
}

运行结果如下:

Derived's Protected CompareTo
Derived's CompareTo
Base's Virtual CompareTo

参考来源 CLR VIA C# 第三版 13.10

版权声明:本文为博主原创文章,未经博主允许不得转载。

隐式和显式接口的区别

隐式和显式接口的区别
  • atzhangzt
  • atzhangzt
  • 2016年09月25日 08:12
  • 309

显式接口实现(C# 编程指南)

 如果类实现两个接口,并且这两个接口包含具有相同签名的成员,那么在类中实现该成员将导致两个接口都使用该成员作为它们的实现。例如:interface IControl{ void Paint();...
  • xyjchinese
  • xyjchinese
  • 2009年04月12日 14:42
  • 193

谨慎使用显式接口方法实现

C#.NET 谨慎使用显式接口方法实现
  • u010533180
  • u010533180
  • 2017年06月12日 08:52
  • 757

接口的显式实现与隐式实现

我们在实现接口时,常常是类继承接口,然后在接口中实现相应的方法。代码如下: interface IOutput { void output(); } cl...
  • xxdddail
  • xxdddail
  • 2014年09月16日 08:33
  • 1974

C#中接口的显式和隐式实现

接口的实现分为:隐式实现和显式实现。如果类或者结构要实现的是单个接口,可以使用隐式实现,如果类或者结构继承了多个接口那么接口中相同名称成员就要显式实现。显示实现是通过使用接口的完全限定名来实现接口成员...
  • NETZHOU
  • NETZHOU
  • 2008年01月22日 11:14
  • 2926

C#.NET隐式和显式接口方法实现幕后发生的故事

C#隐式和显式接口方法的区别
  • u010533180
  • u010533180
  • 2017年06月09日 10:16
  • 1096

C#显式实现接口函数

如果一个类实现了一个接口,他可以选择显示实现这个接口 如果显示实现了接口的话,要调用接口的方法,就必须将类型转换为接口去调用,如果要使用类的实例去调用,就必须为类实现该接口函数。 例如: int...
  • CHALLENG_EVERYTHING
  • CHALLENG_EVERYTHING
  • 2017年03月27日 11:12
  • 494

接口的显示实现和隐式实现一点笔记

隐式实现 不知道成员的归属 显示实现 显示指定成员的归属(通过 接口名.成员 )显式实现避免了成员归属混淆不清的情况,特别是多个接口中有相同的成员,或者接口中成员和类自己的成员冲突的情况。隐式实现...
  • shanghongshen
  • shanghongshen
  • 2015年07月30日 10:42
  • 1182

C# 隐式接口和显示接口的区别

先看个例子 声明两个接口 public interface IFg { int Add(); void Fei(); } pub...
  • w200221626
  • w200221626
  • 2016年07月26日 10:34
  • 1403

C#隐式实现接口成员与显示实现接口成员

对C#隐式实现接口成员与显示实现接口成员的简单说明
  • sirenxiaohuayuan
  • sirenxiaohuayuan
  • 2015年12月29日 14:50
  • 952
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:谨慎使用显式接口方法实现
举报原因:
原因补充:

(最多只允许输入30个字)