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