zoukankan      html  css  js  c++  java
  • Effective C# 学习笔记(二十三)理解接口方法和虚方法的区别

    接口和虚方法的使用的场景各有所指,总的来说实现接口要比重载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方法了,因为继承的父类已实现该方法

    }

  • 相关阅读:
    oracle数据库基础知识汇总—30天(一)
    SQL server
    mySQL 黑窗口运行命令
    MySQL
    常用网址
    常见浏览器JS引擎和内核
    nodejs
    audio标签自动播放在安卓播放正常,IOS不能自动播放
    Microsoft.Office.Interop.Excel Find 操作
    python 的os.getenv("PATH")和os.environ.get("PATH")的区别
  • 原文地址:https://www.cnblogs.com/haokaibo/p/2105434.html
Copyright © 2011-2022 走看看