代码改变世界

Effective C# 学习笔记(二十三)理解接口方法和虚方法的区别

2011-07-13 16:14  小郝(Kaibo Hao)  阅读(404)  评论(0编辑  收藏  举报

接口和虚方法的使用的场景各有所指,总的来说实现接口要比重载virtual方法更具有灵活性。你可以sealed、virtual实现的方法或用 abstract来定义方法契约,甚至可以在实现接口的方法中调用virtual方法来获取子类对父类方法重载的多态控制,和父类对自己实现的统一控制。 父类的虚方法可以提供所有子类对该方法的默认实现,而接口提供了多种方法定义组合(因为可以被多继承),对外提供了更加灵活的暴露契约的方式。

特征:

  1. 接口的方法默认声明为不是Virtual
  2. 子类不能重载父类实现接口的方法

对于此类需求可以使用new 关键字实现,例如有个类实现了接口IMsgIMsg有个方法Message()

所以MyClass必须事先Message()方法。而MyClass又有一个子类继承自它,也实现了Message()方法,但此方法并没有覆盖掉父类的Message()方法。代码如下:

interface IMsg

{

void Message();

}

public class MyClass : IMsg

{

public void Message()

{

Console.WriteLine("MyClass");

}

}

public class MyDerivedClass : MyClass

{

public void Message()

{

Console.WriteLine("MyDerivedClass");

}

}

MyDerivedClass d = new MyDerivedClass();

d.Message(); // prints "MyDerivedClass".

IMsg m = d as IMsg;

m.Message(); // prints "MyClass"

 

若要显示地覆盖掉该方法,应用new关键字来显示覆盖该方法

 

public class MyDerivedClass : MyClass

{

public new void Message()

{

Console.WriteLine("MyDerivedClass");

}

}

MyDerivedClass d = new MyDerivedClass();

d.Message(); // prints "MyDerivedClass".

IMsg m = d as IMsg;

m.Message(); // prints " MyDerivedClass "

 

但是这时只是覆盖了父类实现借口的方法,并没有覆盖掉父类自己的实现,见如下代码:

MyDerivedClass d = new MyDerivedClass();

d.Message(); // prints "MyDerivedClass".

IMsg m = d as IMsg;

m.Message(); // prints "MyDerivedClass"

MyClass b = d;

b.Message(); // prints "MyClass"

 

若要子类在覆盖父类实现接口方法的同时,也覆盖掉父类的方法应声明为virtual的,而子类应以override关键字进行重载,代码如下:

public class MyClass : IMsg

{

public virtual void Message()

{

Console.WriteLine("MyClass");

}

}

public class MyDerivedClass : MyClass

{

public override void Message()

{

Console.WriteLine("MyDerivedClass");

}

}

 

若还要彻底去除父类方法的实现,则应使用abstract关键字,代码如下:

public abstract class MyClass : IMsg

{

public abstract void Message();

}

 

若需要使子类的实现不可被其他更低层次子类重载,则需使用sealed关键字。

public class MyDerivedClass2 : MyClass

{

public sealed override void Message()

{

Console.WriteLine("MyDerivedClass");

}

}

 

此外还可通过在借口方法中,调用virtual声明的方法来实现,子类对接口方法的重载逻辑,同时还可获得父类统一行为的控制。代码如下:

public class MyClass2 : IMsg

{

protected virtual void OnMessage()

{

}

public void Message()

{

OnMessage();//可以用子类重载

Console.WriteLine("MyClass");//父类的统一控制

}

}

 

最后你还可以使用子类继承父类来是实现子类对接口的实现,代码如下:

public class DefaultMessageGenerator

{

public void Message()

{

Console.WriteLine("This is a default message");

}

}

public class AnotherMessageGenerator :DefaultMessageGenerator, IMsg

{

// No explicit Message() method needed. 这里就不用显示实现IMsg方法了,因为继承的父类已实现该方法

}