接口可以多继承,有些时候我们可能需要解决命名空间冲突。 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) { ... } .... }
该用法请慎用,因为子类可能会包含恶意代码。
|