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

原创 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

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

相关文章推荐

c#多线程与异步开发 (上)

项目中需要一些多线程或异步的知识点,找资料时看到了这篇文章,觉得讲的很不错,转载过来,想要学习的可以看原文,原文链接,感谢原作者提供好文章引言本文主要从线程的基础用法,CLR线程池当中工作者线程与I/...
  • suifcd
  • suifcd
  • 2016年01月22日 19:32
  • 4342

C#中的异常捕获机制(try catch finally)

转载自:http://blog.csdn.net/zevin/article/details/6901489 一、C#的异常处理所用到关键字 try 用于检查发生的异常,并帮助发送任何可能的异...

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

C#隐式和显式接口方法的区别

C#入门10.4——显式实现接口

隐式实现接口     既可用接口调用方法,也可用具体类调用方法 显式实现接口 实现接口的方法前不能用访问修饰符public,必须显式指定接口名称     返回值类型 接口名称.接口方法   ...

android学习记录(五)显式Intent与隐式Intent的功能与使用方法解析。

显式Intent与隐式Intent的功能与使用方法解析。   Intent,在中文中的意思是意图。就是想要做的事。   而使用startActivity(Intentintent)或者startAct...

c#中实现接口与显式实现接口的区别

原帖:http://hi.baidu.com/wwang634/blog/item/adfb2ace2d99650592457e17.html   在实现接口的时候,VS提供了两个菜单,一个是"实...

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

接口的实现分为:隐式实现和显式实现。 隐式接口实现:如果类或者结构要实现的是单个接口,可以使用隐式实现。 显式接口实现:如果类或者结构继承了多个接口,那么接口中相同名称成员就要显式...

LabWindowsCVI显式调用DLL的方法

  • 2013年08月03日 20:00
  • 2KB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:谨慎使用显式接口方法实现
举报原因:
原因补充:

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