C#中Override症結字和New症結字的用法詳解。本站提示廣大學習愛好者:(C#中Override症結字和New症結字的用法詳解)文章只能為提供參考,不一定能成為您想要的結果。以下是C#中Override症結字和New症結字的用法詳解正文
C# 說話經由專門設計,以便分歧庫中的基類與派生類之間的版本掌握可以赓續向前成長,同時堅持向後兼容。這具有多方面的意義。例如,這意味著在基類中引入與派生類中的某個成員具有雷同稱號的新成員在 C# 中是完整支撐的,不會招致不測行動。它還意味著類必需顯式聲明某辦法是要重寫一個繼續辦法,照樣一個隱蔽具有相似稱號的繼續辦法的新辦法。
在 C# 中,派生類可以包括與基類辦法同名的辦法。
基類辦法必需界說為 virtual。
可以從派生類中應用 base 症結字挪用基類辦法。
override、virtual 和 new 症結字還可以用於屬性、索引器和事宜中。
默許情形下,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 的對象仍可使用基症結字拜訪 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) { } }
在 Derived 的一個實例中挪用 DoWork 時,C# 編譯器將起首測驗考試使該挪用與最後在 Derived 上聲明的 DoWork 版本兼容。重寫辦法不被視為是在類長進行聲明的,而是在基類上聲明的辦法的新完成。僅當 C# 編譯器沒法將辦法挪用與 Derived 上的原始辦法婚配時,它才測驗考試將該挪用與具有雷同稱號和兼容參數的重寫辦法婚配。例如:
int val = 5; Derived d = new Derived(); d.DoWork(val); // Calls DoWork(double).
因為變量 val 可以隱式轉換為 double 類型,是以 C# 編譯器將挪用 DoWork(double),而不是 DoWork(int)。有兩種辦法可以免此情形。起首,防止將新辦法聲明為與虛辦法同名。其次,可以經由過程將 Derived 的實例強迫轉換為 Base 來使 C# 編譯器搜刮基類辦法列表,從而使其挪用虛辦法。因為是虛辦法,是以將挪用 Derived 上的 DoWork(int) 的完成。例如:
((Base)d).DoWork(val); // Calls DoWork(int) on Derived.
什麼時候應用 Override 和 New 症結字
在 C# 中,派生類中辦法的稱號可與基類中辦法的稱號雷同。可經由過程應用 new 和 override 症結字指定辦法互動的方法。 override 潤飾符 extends 基類辦法,且 new 潤飾符將其“隱蔽”起來。這類差別在本主題中的示例顯示出來。
在掌握台運用法式中,聲明上面的 BaseClass 和 DerivedClass 兩個類. DerivedClass 繼續自 BaseClass。
class BaseClass { public void Method1() { Console.WriteLine("Base - Method1"); } } class DerivedClass : BaseClass { public void Method2() { Console.WriteLine("Derived - Method2"); } }
在 Main 辦法中,聲明變量 bc、dc 和 bcdc。
因為 bc 和 bcdc 具有類型 BaseClass,是以,除非您應用強迫轉換,不然它們只會直接拜訪 Method1。變量 dc 可以拜訪 Method1 和 Method2。上面的代碼演示這些關系。
class Program { static void Main(string[] args) { BaseClass bc = new BaseClass(); DerivedClass dc = new DerivedClass(); BaseClass bcdc = new DerivedClass(); bc.Method1(); dc.Method1(); dc.Method2(); bcdc.Method1(); } // Output: // Base - Method1 // Base - Method1 // Derived - Method2 // Base - Method1 }
接上去,將以下 Method2 辦法添加到 BaseClass。此辦法的簽名與 DerivedClass 中 Method2 辦法的簽名相婚配。
public void Method2() { Console.WriteLine("Base - Method2"); }
因為 BaseClass 如今有 Method2 辦法,是以可認為 BaseClass 變量 bc 和 bcdc 添加第二個挪用語句,以下面的代碼所示。
bc.Method1(); bc.Method2(); dc.Method1(); dc.Method2(); bcdc.Method1(); bcdc.Method2();
當生成項目時,您將看到在 BaseClass 中添加 Method2 辦法將激發正告。正告提醒,DerivedClass 中的 Method2 辦法將 Method2 辦法隱蔽在 BaseClass 中。假如要取得該成果,則建議您應用 Method2 界說中的 new 症結字。或許,可以重定名 Method2 辦法之一來處理正告,但這一直不適用。
在添加 new 之前,運轉該法式以檢查其他挪用語句生成的輸入。顯示以下成果。
輸入:
Base - Method1 Base - Method2 Base - Method1 Derived - Method2 Base - Method1 Base - Method2
new 症結字可以保存生成輸入的關系,但它將撤消正告。具有 BaseClass 類型的變量持續拜訪 BaseClass 成員,具有 DerivedClass 類型的變量起首持續拜訪 DerivedClass 中的成員,然後再斟酌從 BaseClass 繼續的成員.
要制止顯示正告,請向 DerivedClass 中的 Method2 界說添加 new 潤飾符,以下面的示例所示:可在 public 前後添加潤飾符。
public new void Method2() { Console.WriteLine("Derived - Method2"); }
再次運轉該法式以確認沒有更改輸入。還確認正告不再湧現。經由過程應用 new,您斷言您懂得它修正的成員將隱蔽從基類繼續的成員。關於經由過程繼續隱蔽稱號的更多信息,請拜見 new 潤飾符(C# 參考)。
要將此行動與應用 override 的後果停止比較,請將以下辦法添加到 DerivedClass。可在 public 的後面或前面添加 override 潤飾符。
public override void Method1() { Console.WriteLine("Derived - Method1"); }
將 virtual 潤飾符添加到 BaseClass 中的 Method1 的界說。可在 public 的後面或前面添加 virtual 潤飾符。
public virtual void Method1() { Console.WriteLine("Base - Method1"); }
再次運轉項目。特別請留意上面輸入的最初兩行。
輸入:
Base - Method1 Base - Method2 Derived - Method1 Derived - Method2 Derived - Method1 Base - Method2
應用 override 潤飾符使 bcdc 可以或許拜訪 DerivedClass 中界說的 Method1 辦法。平日,這是繼續條理構造中所需的行動。讓具有從派生類創立的值的對象應用派生類中界說的辦法。經由過程應用 override 擴大基類辦法可完成該行動。
上面的代碼包含完全的示例。
using System; using System.Text; namespace OverrideAndNew { class Program { static void Main(string[] args) { BaseClass bc = new BaseClass(); DerivedClass dc = new DerivedClass(); BaseClass bcdc = new DerivedClass(); // The following two calls do what you would expect. They call // the methods that are defined in BaseClass. bc.Method1(); bc.Method2(); // Output: // Base - Method1 // Base - Method2 // The following two calls do what you would expect. They call // the methods that are defined in DerivedClass. dc.Method1(); dc.Method2(); // Output: // Derived - Method1 // Derived - Method2 // The following two calls produce different results, depending // on whether override (Method1) or new (Method2) is used. bcdc.Method1(); bcdc.Method2(); // Output: // Derived - Method1 // Base - Method2 } } class BaseClass { public virtual void Method1() { Console.WriteLine("Base - Method1"); } public virtual void Method2() { Console.WriteLine("Base - Method2"); } } class DerivedClass : BaseClass { public override void Method1() { Console.WriteLine("Derived - Method1"); } public new void Method2() { Console.WriteLine("Derived - Method2"); } } }
以下示例顯示了分歧高低文中的相似行動。該示例界說了三個類:一個名為 Car 的基類,和兩個由其派生的 ConvertibleCar 和 Minivan。基類中包括 DescribeCar 辦法。該辦法給出了對一輛車的根本描寫,然後挪用 ShowDetails 來供給其他的信息。這三個類中的每個類都界說了 ShowDetails 辦法。 new 潤飾符用於界說 ConvertibleCar 類中的 ShowDetails。 override 潤飾符用於界說 Minivan 類中的 ShowDetails。
// Define the base class, Car. The class defines two methods, // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived // class also defines a ShowDetails method. The example tests which version of // ShowDetails is selected, the base class method or the derived class method. class Car { public void DescribeCar() { System.Console.WriteLine("Four wheels and an engine."); ShowDetails(); } public virtual void ShowDetails() { System.Console.WriteLine("Standard transportation."); } } // Define the derived classes. // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails // hides the base class method. class ConvertibleCar : Car { public new void ShowDetails() { System.Console.WriteLine("A roof that opens up."); } } // Class Minivan uses the override modifier to specify that ShowDetails // extends the base class method. class Minivan : Car { public override void ShowDetails() { System.Console.WriteLine("Carries seven people."); } }
該示例測試被挪用的 ShowDetails 版本。以下辦法,TestCars1 為每一個類供給了一個實例,並在每一個實例上挪用 DescribeCar。
public static void TestCars1() { System.Console.WriteLine("\nTestCars1"); System.Console.WriteLine("----------"); Car car1 = new Car(); car1.DescribeCar(); System.Console.WriteLine("----------"); // Notice the output from this test case. The new modifier is // used in the definition of ShowDetails in the ConvertibleCar // class. ConvertibleCar car2 = new ConvertibleCar(); car2.DescribeCar(); System.Console.WriteLine("----------"); Minivan car3 = new Minivan(); car3.DescribeCar(); System.Console.WriteLine("----------"); }
TestCars1 生成以下輸入:特別請留意 car2 的成果,該成果能夠不是您所需的內容。對象的類型是 ConvertibleCar,但 DescribeCar 不會拜訪 ConvertibleCar 中界說的 ShowDetails 版本,由於辦法已聲明包括 new 潤飾符,而不是 override 潤飾符。是以,ConvertibleCar 對象顯示與 Car 對象雷同的解釋。比擬 car3 的成果,它是一個 Minivan 對象。在這類情形下,在 Minivan 類中聲明的 ShowDetails 辦法重寫 Car 類中聲明的 ShowDetails 辦法,顯示的解釋描寫微型面包車。
// TestCars1 // ---------- // Four wheels and an engine. // Standard transportation. // ---------- // Four wheels and an engine. // Standard transportation. // ---------- // Four wheels and an engine. // Carries seven people. // ----------
TestCars2 創立 Car 類型的對象列表。對象的值由 Car、ConvertibleCar 和 Minivan 類實例化而來。 DescribeCar 是挪用列表中的每一個元素。以下代碼顯示了 TestCars2 的界說。
public static void TestCars2() { System.Console.WriteLine("\nTestCars2"); System.Console.WriteLine("----------"); var cars = new List<Car> { new Car(), new ConvertibleCar(), new Minivan() }; foreach (var car in cars) { car.DescribeCar(); System.Console.WriteLine("----------"); } }
顯示以下輸入。請留意,此輸入與由 TestCars1 顯示的輸入雷同。 ConvertibleCar 類的 ShowDetails 辦法不被挪用,不管對象的類型是 ConvertibleCar,如在 TestCars1 中,照樣 Car,如在 TestCars2 中。相反,car3 在兩種情形下都從 Minivan 類挪用 ShowDetails 辦法,不管它具有類型 Minivan 照樣類型 Car。
// TestCars2 // ---------- // Four wheels and an engine. // Standard transportation. // ---------- // Four wheels and an engine. // Standard transportation. // ---------- // Four wheels and an engine. // Carries seven people. // ----------
完成示例的辦法 TestCars3 和 TestCars4。這些辦法直接挪用 ShowDetails,起首從宣告具有類型 ConvertibleCar 和 Minivan (TestCars3) 的對象挪用,然後從具有類型 Car (TestCars4) 的對象挪用。以下代碼界說了這兩種辦法。
public static void TestCars3() { System.Console.WriteLine("\nTestCars3"); System.Console.WriteLine("----------"); ConvertibleCar car2 = new ConvertibleCar(); Minivan car3 = new Minivan(); car2.ShowDetails(); car3.ShowDetails(); } public static void TestCars4() { System.Console.WriteLine("\nTestCars4"); System.Console.WriteLine("----------"); Car car2 = new ConvertibleCar(); Car car3 = new Minivan(); car2.ShowDetails(); car3.ShowDetails(); }
該辦法發生上面的輸入,它對應本主題中第一個示例的成果。
// TestCars3 // ---------- // A roof that opens up. // Carries seven people. // TestCars4 // ---------- // Standard transportation. // Carries seven people.
以下代碼顯示了全部項目及其輸入。
using System; using System.Collections.Generic; using System.Linq; using System.Text; namespace OverrideAndNew2 { class Program { static void Main(string[] args) { // Declare objects of the derived classes and test which version // of ShowDetails is run, base or derived. TestCars1(); // Declare objects of the base class, instantiated with the // derived classes, and repeat the tests. TestCars2(); // Declare objects of the derived classes and call ShowDetails // directly. TestCars3(); // Declare objects of the base class, instantiated with the // derived classes, and repeat the tests. TestCars4(); } public static void TestCars1() { System.Console.WriteLine("\nTestCars1"); System.Console.WriteLine("----------"); Car car1 = new Car(); car1.DescribeCar(); System.Console.WriteLine("----------"); // Notice the output from this test case. The new modifier is // used in the definition of ShowDetails in the ConvertibleCar // class. ConvertibleCar car2 = new ConvertibleCar(); car2.DescribeCar(); System.Console.WriteLine("----------"); Minivan car3 = new Minivan(); car3.DescribeCar(); System.Console.WriteLine("----------"); }
輸入:
TestCars1 ---------- Four wheels and an engine. Standard transportation. ---------- Four wheels and an engine. Standard transportation. ---------- Four wheels and an engine. Carries seven people. ----------
public static void TestCars2() { System.Console.WriteLine("\nTestCars2"); System.Console.WriteLine("----------"); var cars = new List<Car> { new Car(), new ConvertibleCar(), new Minivan() }; foreach (var car in cars) { car.DescribeCar(); System.Console.WriteLine("----------"); } }
輸入:
TestCars2 ---------- Four wheels and an engine. Standard transportation. ---------- Four wheels and an engine. Standard transportation. ---------- Four wheels and an engine. Carries seven people. ----------
public static void TestCars3() { System.Console.WriteLine("\nTestCars3"); System.Console.WriteLine("----------"); ConvertibleCar car2 = new ConvertibleCar(); Minivan car3 = new Minivan(); car2.ShowDetails(); car3.ShowDetails(); }
輸入:
TestCars3 ---------- A roof that opens up. Carries seven people.
public static void TestCars4() { System.Console.WriteLine("\nTestCars4"); System.Console.WriteLine("----------"); Car car2 = new ConvertibleCar(); Car car3 = new Minivan(); car2.ShowDetails(); car3.ShowDetails(); } // Output: // TestCars4 // ---------- // Standard transportation. // Carries seven people. } // Define the base class, Car. The class defines two virtual methods, // DescribeCar and ShowDetails. DescribeCar calls ShowDetails, and each derived // class also defines a ShowDetails method. The example tests which version of // ShowDetails is used, the base class method or the derived class method. class Car { public virtual void DescribeCar() { System.Console.WriteLine("Four wheels and an engine."); ShowDetails(); } public virtual void ShowDetails() { System.Console.WriteLine("Standard transportation."); } } // Define the derived classes. // Class ConvertibleCar uses the new modifier to acknowledge that ShowDetails // hides the base class method. class ConvertibleCar : Car { public new void ShowDetails() { System.Console.WriteLine("A roof that opens up."); } } // Class Minivan uses the override modifier to specify that ShowDetails // extends the base class method. class Minivan : Car { public override void ShowDetails() { System.Console.WriteLine("Carries seven people."); } } }