共用方式為


使用 Override 和 New 關鍵詞進行版本控制 (C# 程式設計手冊)

C# 語言的設計目的是讓不同連結庫中 基底 類別與衍生類別之間的版本控制可以進化和維護回溯相容性。 例如,這表示在基類中引進與衍生 類別 中成員同名的新成員完全受到 C# 的支援,而且不會導致非預期的行為。 這也表示類別必須明確指出方法是要覆寫繼承的方法,還是方法是否為隱藏類似名稱繼承方法的新方法。

在 C# 中,衍生類別可以包含名稱與基類方法相同的方法。

  • 如果衍生類別中的 方法前面沒有 新的override 關鍵詞,編譯程式會發出警告,而且方法的行為會 new 如同關鍵詞存在一樣。

  • 如果衍生類別中的 方法前面加上 new 關鍵詞,則會將 方法定義為與基類中方法無關。

  • 如果衍生類別中的 方法前面加上 override 關鍵詞,衍生類別的物件將會呼叫該方法,而不是基類方法。

  • 若要將 override 關鍵詞套用至衍生類別中的 方法,必須將基類方法定義為 虛擬

  • 基類方法可以使用 關鍵詞從衍生類別 base 內呼叫。

  • overridevirtualnew 關鍵字也可以套用至屬性、索引器和事件。

根據預設,C# 方法不是虛擬的。 如果方法宣告為虛擬,任何繼承方法的類別都可以實作自己的版本。 若要讓方法成為虛擬, virtual 修飾詞會用於基類的方法宣告中。 然後,衍生類別可以使用 override 關鍵詞覆寫基底類別中的虛擬方法,或使用 new 關鍵詞隱藏基底類別中的虛擬方法。 如果既未指定 override 關鍵詞,也未指定 new 關鍵詞,編譯程式將會發出警告,然後衍生類別中的方法將會隱藏基類中的方法。

為了在實務上示範這一點,假設公司 A 已建立名為 GraphicsClass的類別,您的程式會使用此類別。 以下是 GraphicsClass

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
}

您的公司會使用此類別,並使用它來衍生您自己的類別,並新增新的方法:

class YourDerivedGraphicsClass : GraphicsClass
{
    public void DrawRectangle() { }
}

在公司 A 發行新版本 GraphicsClass之前,您的應用程式使用時不會發生問題,這類似於下列程式代碼:

class GraphicsClass
{
    public virtual void DrawLine() { }
    public virtual void DrawPoint() { }
    public virtual void DrawRectangle() { }
}

GraphicsClass新版本現在包含名為 DrawRectangle的方法。 一開始,什麼都沒有發生。 新版本仍然與舊版本二進位相容。 您部署的任何軟體都會繼續運作,即使新類別安裝在這些計算機系統上也一樣。 衍生類別中對方法DrawRectangle的任何現有呼叫將會繼續參考您的版本。

不過,一旦您使用新版本 GraphicsClass重新編譯應用程式,您就會收到來自編譯程式 CS0108 的警告。 此警告提醒您,需要仔細考慮方法 DrawRectangle 在應用程式中應如何運作。

如果您想要讓方法覆寫新的基類方法,請使用 override 關鍵詞:

class YourDerivedGraphicsClass : GraphicsClass
{
    public override void DrawRectangle() { }
}

override關鍵詞可確保衍生自 YourDerivedGraphicsClass 的任何物件都會使用 的DrawRectangle衍生類別版本。 衍生自 YourDerivedGraphicsClass 的物件仍然可以使用 base 關鍵字來存取基類的 DrawRectangle 版本。

base.DrawRectangle();

如果您不想讓 方法覆寫新的基類方法,則適用下列考慮。 若要避免兩種方法之間的混淆,您可以重新命名方法。 這很耗時且容易出錯,在某些情況下並不實用。 不過,如果您的項目相對較小,您可以使用 Visual Studio 的重構選項來重新命名方法。 如需詳細資訊,請參閱重構類別和類型(類別設計工具)。

或者,您可以使用衍生類別定義中的 關鍵詞 new 來防止警告:

class YourDerivedGraphicsClass : GraphicsClass
{
    public new void DrawRectangle() { }
}

new使用 關鍵詞會告知編譯程式您的定義隱藏基類中包含的定義。 此為預設行為。

覆寫和方法選擇

在類別上命名方法時,如果有多個方法與呼叫相容,C# 編譯程式會選取要呼叫的最佳方法,例如當有兩個方法具有相同名稱,且參數與傳遞的參數相容時。 下列方法會相容:

public class Derived : Base
{
    public override void DoWork(int param) { }
    public void DoWork(double param) { }
}

當在 DoWork 的實例上呼叫 Derived 時,C# 編譯器會先嘗試讓呼叫與 DoWork 上原本宣告的 Derived 版本相容。 覆寫方法不會被視為針對類別宣告的,它們是針對基類宣告之方法的新的實作。 只有在 C# 編譯器無法比對在 Derived 的原始方法的方法呼叫時,才會嘗試將呼叫比對到具有相同名稱和相容參數的重載方法。 例如:

int val = 5;
Derived d = new();
d.DoWork(val);  // Calls DoWork(double).

因為變數 val 可以隱含地轉換為 double,因此 C# 編譯器會呼叫 DoWork(double) ,而不是 DoWork(int)。 有兩種方式可以避免這種情況。 首先,請避免使用與虛擬方法相同的名稱來宣告新的方法。 其次,您可以指示 C# 編譯器透過將 Derived 實例轉換為 Base 來搜尋基類方法清單,進而呼叫虛擬方法。 因為此方法是虛擬的,因此會呼叫DoWork(int)Derived上的實作。 例如:

((Base)d).DoWork(val);  // Calls DoWork(int) on Derived.

如需newoverride的更多範例,請參閱瞭解何時使用"Override"和"New Keywords"

另請參閱