首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

C# 多態與 new 關鍵字深度解析:隱藏、覆寫與介面重新實作

     編輯:關於C語言

多態基礎:virtual / override

class Base
{
    public virtual void PrintStatus() 
        => Console.WriteLine("Base.PrintStatus");
}

class Derived1 : Base
{
    public override void PrintStatus() 
        => Console.WriteLine("Derived1.PrintStatus");
}

統一處理:

void DisplayStatus(Base[] items)
{
    foreach (var b in items) b.PrintStatus(); // 動態綁定
}

new 關鍵字:隱藏而非覆寫

class Derived2 : Base
{
    public new void PrintStatus() 
        => Console.WriteLine("Derived2.PrintStatus (new 隱藏)");
}

行為差異示範

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

// 輸出:
// Base.PrintStatus
// Derived1.PrintStatus
// Base.PrintStatus  ← Derived2 以 Base 型別調用時,調用的是 Base 版本!

new 只是隱藏基類成員,不參與虛擬調度。可通過型別轉換「解封」:

Base d2 = new Derived2();
d2.PrintStatus(); // 輸出 Base.PrintStatus

// Derived2 內部可用 base 訪問被隱藏成員
base.PrintStatus();

靜態成員隱藏

class Base { public static void S() => Console.WriteLine("Base.S"); }
class Derived : Base { public new static void S() => Console.WriteLine("Derived.S"); }

// 必須透過類別名稱調用
Base.S();      // Base.S
Derived.S();   // Derived.S

介面重新實作:new 的進階用法

interface IFace { void PrintStatus(); }

class Base : IFace
{
    public virtual void PrintStatus() => Console.WriteLine("Base");
}

class Derived2 : Base, IFace
{
    public new void PrintStatus() => Console.WriteLine("Derived2 (new + 介面重新實作)");
}

透過介面調用時,new 方法參與動態綁定:

IFace[] fs = { new Base(), new Derived1(), new Derived2() };
foreach (var f in fs) f.PrintStatus();

// 輸出:
// Base
// Derived1
// Derived2 (new + 介面重新實作)  ← 介面綁定生效!

原理:new 切斷與 Base.PrintStatus 的虛擬槽關聯,但 Derived2 重新宣告實作 IFace,編譯器將其視為介面槽的新實作。

設計原則:誰的問題?

  • 若 Base 宣告 virtual 期望多態,Derived2 用 new 違背契約 → Derived2 應改名或用 override
  • 若 Derived2 確實不想參與多態 → Base 應考慮移除 virtual 或改為 abstract 強制衍生類實作

改良:抽象基類強制契約

abstract class Base { public abstract void PrintStatus(); }

class Derived3 : Base 
{ 
    public override void PrintStatus() => Console.WriteLine("Derived3 (原 Base 實作下移)"); 
}

// 此時 Derived2 若仍用 new PrintStatus() → 編譯錯誤,強制修正

真實世界案例:Stream.CanSeek

Stream.Seek 為 abstract,但 NetworkStream 不支援定位,調用拋 NotSupportedException。設計模式:

  • 提供 CanSeek、CanRead、CanWrite 屬性讓調用者預檢
  • 調用者責任:if (stream.CanSeek) stream.Seek(...); else 降級處理

總結

關鍵字語義虛擬槽介面槽
virtual開放覆寫新增/繼承可實作
override覆寫基類虛擬/抽象替換替換
new隱藏基類同名成員切斷關聯可重新實作介面
abstract強制衍生類實作無實作槽需實作

核心心法:virtual = 契約承諾,override = 履行契約,new = 拒絕契約 (或另闢蹊徑)。設計時優先用 abstract 強制語義清晰,謹慎使用 new 並配合介面重新實作解耦。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved