1. 程式人生 > >CLR via C#學習筆記-第六章-對類型進行版本控制時的虛方法的處理

CLR via C#學習筆記-第六章-對類型進行版本控制時的虛方法的處理

兩種 編譯器 當前 new 學習筆記 on() 定義 類定義 sealed

6.6.3 對類型進行版本控制時的虛方法的處理

如果類型要作為基類型使用,增加或修改它的成員時務必非常小心。

隱藏基類的同名實例方法

假定CompanyA定義了Phone類型

namespace CompanyA
{
    public class Phone
    {
        public void Dial
        {
            Console.WriteLine("Phone.Dial");
            //在這裏執行撥號操作
        }
    }
}

再假定CompanyB定義了BetterPhone類型,使用CompanyA的Phone類型作為基類型

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine(
"BetterPhone.EstablishConnection"); //在這裏執行建立連接的操作 } } }

CompanyB編譯上述代碼時,C#編譯器生成以下警告消息:

warning CS0108:"CompanyB.BetterPhone.Dial()"隱藏了繼承的成員"COmpanyA.Phone.Dial"
如果是有意隱藏,請使用關鍵字new

該警告告訴開發人員,BetterPhone類正在定義這個Dial方法,他會隱藏Phone類定義的Dial。

解決辦法就是在BetterPhone類中定義Dial時,在前面加一個new關鍵字。

以下是改正後的BetterPhone類

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public new void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在這裏執行建立連接的操作
        }
    }
}

現在CompanyB能正常使用BetterPhone.Dial。

以下是CompanyB可能寫的一些示例代碼。

public sealed class Program()
{
    public static void Main
    {
        CompanyB.BetterPhone phone=new CompanyB.BetterPhone();
        phone.Dial();
    }
}

運行以上代碼,輸出結果如下所示

BetterPhone.Dial
BetterPhone.EstablishConnection
Phone.Dial

隱藏基類同名的虛方法

現在,假定幾家公司計劃使用CompanyA的Phone類型,再假定這幾家公司都認為在Dial方法中建立連接的主意非常好。CompanyA決定對這個Phone類進行修訂。

namespace CompanyA
{
    public class Phone
    {
        public void Dial
        {
            Console.WriteLine("Phone.Dial");
            EstablishConnection();
            //在這裏執行撥號操作
        }
        protected virtual void EstablishConnection()
        {
            Console.WriteLine("Phone.EstablishConnection");
            //在這裏執行建立連接的操作
        }
    }
}

現在,一旦CompanyB編譯他的BetterPhone類型就會生成以下警告

warning CS0114:"CompanyB.BetterPhone.EstablishConnection()"
將隱藏繼承的成員"CompanyA.Phone.EstablishConnection()"
若要使當前成員重寫該類型,請天假關鍵字override否則,添加關鍵字new。

如果CompanyB認定EstablishConnection方法在兩個類型的語義不一致,

CompanyB可以告訴編譯器使用BetterPhone類中定義的Dial和EstablishConnection方法,他們與基類型Phone中的沒有關系。

CompanyB可以為EstablishConnection方法添加new關鍵字來告訴編譯器這一點。

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        public new void Dial
        {
            Console.WriteLine("BetterPhone.Dial");
            EstablishConnection();
            base.Dial();
        }
        protected new virtual void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在這裏執行建立連接的操作
        }
    }
}

在這段代碼中,關鍵字new告訴編譯器生成元數據,讓CLR知道BetterPhone類型的EstablishConnection方法應被視為由BetterPhone類型引入的新函數。

執行相同的應用程序代碼,輸出結果如下所示

BetterPhone.Dial
BetterPhone.EstablishConnection
Phone.Dial
Phone.EstablishConnection

如果更改方法名只會造成源代碼發生適度更新,就應該更改方法名,避免Dial和EstablishConnection方法的兩種不同含義是開發人員產生混淆。

將派生類虛方法改為重寫基類的方法,實例方法繼承自基類

還有一個辦法是,CompanyB可以獲得CompanyA的新版本Phone類型,並確定Dial和EstablishConnection在Phone中的語義正好是他們所希望的。

這種情況,CompanyB可以通過完全移除Dial方法來修改他們的BetterPhone類型。另外,由於CompanyB希望告訴編譯器兩類型的EstablishConnection方法是相關的,必須移除new關鍵字。為了準確表達意圖,CompanyB的開發人員必須將BetterPhone的EstablishConnection方法由virtual改編為override。以下代碼展示了新版本的BetterPhone類。

namespace CompanyB
{
    public class BetterPhone:CompanyA.Phone
    {
        //刪除Dial方法,從基類繼承
        protected override void EstablishConnection()
        {
            Console.WriteLine("BetterPhone.EstablishConnection");
            //在這裏執行建立連接的操作
        }
    }
}

執行相同的應用程序代碼,輸出結果如下所示。

Phone.Dial
BetterPhone.EstablishConnection

CLR via C#學習筆記-第六章-對類型進行版本控制時的虛方法的處理