程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> C# >> C#基礎知識 >> 漫談C#編程中的多態與new關鍵字

漫談C#編程中的多態與new關鍵字

編輯:C#基礎知識

  1. 你通常怎樣用多態?

  假設我有一個類,裡面有一個 PrintStatus 方法,用於打印實例的當前狀態,我希望該類的派生類都帶有一個 PrintStatus 方法,並且這些方法都用於打印其實例的當前狀態。那麼我會這樣表達我的願望:

  

// Code #01
class Base
{
 public virtual void PrintStatus()
 {
  Console.WriteLine("public virtual void PrintStatus() in Base");
 }
}

  於是我可以寫一個這樣的方法:

  

// Code #02
public void DisplayStatusOf(Base[] bs)
{
 foreach (Base b in bs)
 {
  b.PrintStatus();
 }
}

  bs 中可能包含著不同的 Base 的派生類,但我們卻可以忽略這些“個性”而使用一種統一的方式來處理某事。在 .NET 2.0 中,XmlReader 的 Create 有這樣一個版本:

  

public static XmlReader Create(Stream input);

  你可以向 Create 傳遞任何可用的“流”,例如來自文件的“流”(FileStream)、來自內存的“流”(MemoryStream)或來自網絡的“流”(NetworkStream)等。雖然每一中“流”的工作細節都不同,但我們卻使用一種統一的方式來處理這些“流”。

  2. 假如有人不遵守承諾...

  DisplayStatusOf 隱含著這樣一個假設:bs 中如果存在派生類的實例,那麼該派生類應該重寫 PrintStatus,當然必須加上 override 關鍵字:

  

// Code #03
class Derived1 : Base
{
 public override void PrintStatus()
 {
  Console.WriteLine("public override void PrintStatus() in Derived1");
 }
}

  你可以把這看作一種承諾、約定,直到有人沉不住氣...

  

// Code #04
class Derived2 : Base
{
 public new void PrintStatus()
 {
  Console.WriteLine("public new void PrintStatus() in Derived2");
 }
}

  假設我們有這樣一個數組: // Code #05

  

Base[] bs = new Base[]
{
 new Base(),
 new Derived1(),
 new Derived2()
};

  把它傳遞給 DisplayStatusOf,則輸出是:

  

// Output #01
// public virtual void PrintStatus() in Base
// public override void PrintStatus() in Derived1
// public virtual void PrintStatus() in Base

  從輸出結果中很容易看出 Derived2 並沒有按照我們期望的去做。但你無需驚訝,這是由於 Derived2 的設計者沒有“遵守約定”的緣故。

  3. new:封印咒術

  new 似乎給人一種這樣的感覺,它的使用者喜歡打破別人的約定,然而,如果使用恰當,new 可以彌補基類設計者的“短見”。在 Creating a Data Bound ListView Control 中,Rockford Lhotka 就示范了如何封印原來的 ListView.Columns,並使自行添加的返回 DataColumnHeaderCollection 的 Columns 取而代之。

  從 Output #01 中我們可以看到,new 只是把 Base.PrintStatus 封印起來而不是消滅掉,你可以解除封印然後進行訪問。對於 Derived2 的使用者,解封的方法是把 Derived2 的實例轉換成 Base 類型:

  

// Code #06
Base d2 = new Derived2();
d2.PrintStatus();
// Output #02
// public virtual void PrintStatus() in Base
而在 Derived2 內部,你可以透過 base 來訪問:
// Code #07
base.PrintStatus();

  這種方法是針對實例成員的,如果被封印的成員是靜態成員的話,就要透過類名來訪問了。

  4. 假如 Base.PrintStatus 是某個接口的隱式實現...

  假如 Base 實現了一個 IFace 接口:

  

// Code #08
interface IFace
{
 void PrintStatus();
}
class Base : IFace
{
 public virtual void PrintStatus()
 {
  Console.WriteLine("public virtual void PrintStatus() in Base");
 }
}

  我們只需要讓 Derived2 重新實現 IFace:

  

// Code #09
class Derived2 : Base, IFace
{
 public new void PrintStatus()
 {
  Console.WriteLine("public new void PrintStatus() in Derived2");
 }
}

  Derived1 保持不變。則把:

  

// Code #10
IFace[] fs = new IFace[]
{
 new Base(),
 new Derived1(),
 new Derived2(),
}

  傳遞給:

  • 首頁
  • 上一頁
  • 1
  • 2
  • 下一頁
  • 尾頁
  • 共2頁
  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved