C#中的显式接口成员实现(explicit interface member implementation)

在C#中不可以继承多个基类,但是可以实现多个接口。但是当实现的不同接口中拥有相同名称的方法时,我们就必须使用限定的完全名称来在类中实现接口的方法,比如:

public   interface  IMySQL
{
string GetConnStr() {}
}


public   interface  IOracle
{
string GetConnStr() {}
}


public   class  DB: IMySQL, IOracle
{
string IMySQL.GetConnStr() {}

string IOracle.GetConnStr() {}

public string GetConnStr() {}
}

在上面的代码中,两个接口IMySQL、IOracle有一个相同名称的方法GetConnStr,当类DB继承这两个接口时,必须使用完全限定名称来实现,也就是“接口名.方法名”。代码中的IMySQL.GetConnStr()和IOracle.GetConnStr()分别是接口IMySQL和IOracle中GetConnStr方法的实现(显式接口继承),而第三个GetConnStr方法则与两个接口没有任何关系(如果删除IMySQL.GetConnStr方法,第三个GetConnStr方法则成为IMySQL接口的实现方法)。

注意在两个显式接口成员实现的方法前面并没有public或private之类的访问限定符,这是因为有时候它们是public,有时候又是private,为什么这样说呢,请先看下例:

static   void  InvokeMethod()
{
DB db 
= new DB();

string connectionString;

connectionString 
= db.GetConnStr();

connectionString 
= ((IMySQL)db).GetConnStr();

connectionString 
= ((IOracle)db).GetConnStr();
}

在此的第一个GetConnStr方法调用(connectionString = db.GetConnStr())实际上是调用了开始代码段中的第三个GetConnStr方法,即与任何接口无关的那个方法。在这个调用发生时,两个接口的GetConnStr方法是私有的(private),继承接口的类的实例并不能调用接口的方法。而当类的实例被转化成接口的类型时,GetConnStr方法成为了公开方法(public)。

 接口的灵活性也会伴随着编译时类型安全的代价,因为很多的接口都接受System.Object类型的参数或者返回一个System.Object类型的值,比如常用的IComparable接口:

public   interface  IComparable
{
      
// Methods
      int CompareTo(object obj);
}


当我们定义一个值类型实现IComparable接口的CompareTo方法时:

struct  ValueType : IComparable
{
      
private Int32 x;
      
public ValueType(Int32 x) this.x = x; }
      
public Int32 CompareTo(Object obj)
      
{
            
return (x - ((ValueType)obj).x);
      }

}

然后调用这个类型的CompareTo方法:

static   void  Main()
{
      ValueType v 
= new ValueType(0);
      Object o 
= new Object();

      Int32 n 
= v.CompareTo(o);
}

上面这段代码中声明了一个Object类型的对象o,然后调用ValueType的CompareTo方法来接受o进行比较,这在编译期间没有任何错误发生,但是当运行时就会出现类型转换错误,这是因为o并不是ValueType类型,并没有一个x的字段。

CLR提供的显式接口成员实现可以帮助我们在编译时获得错误提示,从而避免程序运行后发生错误,提高类型安全,请看下面代码:

struct  ValueType : IComparable
{
      
private Int32 x;
      
public ValueType(Int32 x) this.x = x; }

      
public Int32 CompareTo(ValueType vt)
      
{
            
return (x - vt.x);
      }


      Int32 IComparable.CompareTo(Object obj)
      
{
            
return CompareTo((ValueType)obj);
      }

}

在这段代码中提供了两个版本的CompareTo方法,第二个就是我们前面提到过的显式接口成员实现,让我们来看这样做的好处:

ValueType vt1  =   new  ValueType( 1 );
ValueType vt2 
=   new  ValueType( 2 );
Int32 n;

=  vt1.CompareTo(vt2);
=  vt2.CompareTo( new  Object());       // compile-time error

// 调用接受Object类型参数的IComparable.CompareTo方法,vt2被进行装箱操作
=  ((IComparable)vt1).CompareTo(vt2);

在第一次调用(n = vt1.CompareTo(vt2))中,使用的是接受ValueType类型参数的CompareTo方法,这样CLR就会在编译时进行类型检查,保证了类型安全,而之后的n = vt2.CompareTo(new Object());则会碰到编译时错误。如果我们想调用接受Object类型参数的CompareTo方法,就必须获得IComparable类型的一个引用,所以在最后一句中我们进行了类型转换并调用CompareTo方法。但是在最后一次的调用中vt1首先被装箱转换成IComparable类型,接下来因为IComparable.CompareTo方法接受Object类型参数,所以vt2被装箱转换成Object类型。

综上所述,显式接口成员实现帮助我们增强类型安全(无论是对值类型还是引用类型),对于值类型,还可以避免装箱操作,减少性能损耗。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值