接口可以多继承,有些时候我们可能需要解决命名空间冲突。
using System;using System.Linq;using System.Text;namespace Test{public interface IDraw1{void Draw();}public interface IDraw2{void Draw();}class MyDraw : IDraw1, IDraw2{public void Draw(){Console.WriteLine("Drawing...");}}class Program{static void Main(string[] args){MyDraw md = new MyDraw();md.Draw();((IDraw1)md).Draw();((IDraw2)md).Draw();Console.ReadKey();}}}
以上的方式是隐式的实现接口,这里就出现了一个问题:只提供一个Draw()方法的实现,导致了两个接口都使用该成员作为它们的实现。其运行结果如下:
显然这不是我们想要的,可以使用显式接口实现语法解决命名空间冲突,其代码如下:
using System;using System.Linq;using System.Text;namespace Test{public interface IDraw1{void Draw();}public interface IDraw2{void Draw();}class MyDraw : IDraw1, IDraw2{void IDraw1.Draw(){Console.WriteLine("Drawing1...");}void IDraw2.Draw(){Console.WriteLine("Drawing2...");}}class Program{static void Main(string[] args){MyDraw md = new MyDraw();((IDraw1)md).Draw();((IDraw2)md).Draw();Console.ReadKey();}}}
显式实现成员是隐式私有的,这些成员在对象级别就不可用,我们必须显示转换来访问需要的功能。(使用if(obj is IObjType)先判断下类型再进行转换是个不错的选择)
其运行结果如下:
可见:
1 隐式实现接口,接口和类(实现接口的类)都可以访问类中的方法;
2 显式实现接口,C#没有提供任何语法,来在派生类中调用基类中显式实现的接口成员,只有通过接口来访问类中的方法;
3 显式实现接口,可以帮助我们在对象级别隐藏高级成员。但是,不要把显式实现当做安全壁垒。只要把实例强制转换为接口,任何代码都可以调用此类的方法。
何时使用显式接口实现
1 接口多继承,引起命名空间冲突。
2 当需要在开发过程中定义一些只供内部使用的接口时。
3 类型已经有了一个方法,该方法与接口方法的名字和参数相同,但返回类型不同。
4 如果希望接口成员只能通过该接口来调用。例如ICollection<T>.IsReadonly的主要目的是为了让数据绑定基础设施通过ICollection<T>接口来访问。在实现该接口类型时,几乎不会直接访问该方法。因此,IList<T>显式地实现了该接口成员。
5 模拟变体(variance)。(在被覆盖的成员中改变参数或返回值的类型。)例如,为了创建强类型集合,IList的实现通常会显式地实现(隐藏)弱类型成员,并增加强类型的公有成员,以改变参数和返回值的类型。
public class StringCollection:IList{public string this[int index]{...}object IList.this[int index]{...}...}
6 在需要隐藏一个成员并增加另一个名字更合适的等价成员时。这等同对成员进行重命名。例如,System.IO.FileStraem显式地实现了IDispossable.Dispose,并将它重命名为Close。
public class FileStream:IDisposable{void IDisposable.Dispose(){Close();}public void Close(){...}...}
这样的用法并不推荐,重命名一个好的名字与沿用一个糟糕的名字相比,可能会引起更大的混乱。例如:Close()是应该调用IDispossable.Dispose()还是某个其它方法?开发人员是否知道这两个函数实际上是同样的东西?是否有潜在的调用顺序?这些问题可能会困扰开发人员。
注意,如果希望让对显式实现的接口成员功能进行定制,那么要为其提供具有相同功能的受保护的虚成员。显式实现的成员不能被覆盖。虽然可以重新定义它们,但之后的子类型就不可能再调用基类方法的实现了。
[Serializable]public class List<T>:ISerializable{void ISerializable.GetObjectData(SerializationInfo info,StreamingContext context){GetObjectData(info,context);}protected virtual void GetObjectData(SerializationInfo info,StreamingContext context){...}....}
该用法请慎用,因为子类可能会包含恶意代码。
联系客服