上一篇文章我们讲解了隐式和显式接口背后发生的故事(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