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

C# new 關鍵字三大用法深度解析:運算子、修飾詞、泛型約束

     編輯:關於C語言

前言

new 是 C# 中出現頻率最高的關鍵字之一,但許多開發者只熟悉「建立物件」這一面。實際上它還扮演「隱藏基底成員」修飾詞與「泛型型別約束」兩種完全不同的角色。本文將三大用法一次釐清,並附上常見誤區與最佳實踐。

用法一:運算子——建立物件與呼叫建構函式

// 參考型別:在堆疊配置記憶體,回傳參考
var list = new List();

// 實值型別:在堆疊/內嵌配置,回傳實值副本
var point = new Point(10, 20);

// 匿名型別
var anon = new { Name = "Tom", Age = 25 };

// 陣列
var arr = new int[3] { 1, 2, 3 };
var arr2 = new[] { "A", "B", "C" }; // 型別推論

// 物件初始化器(C# 3.0+)
var user = new User { Id = 1, Name = "Jerry" };

// 集合初始化器
var dict = new Dictionary { [1] = "One", [2] = "Two" };

重點:new 運算子不能被多載,行為由 CLR 固定;結構體若未顯式定義建構函式,會自動擁有無參建構函式(將所有欄位歸零)。

用法二:修飾詞——隱藏基底類別成員

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

public class Derived : Base
{
    // 1. 隱藏虛擬方法(不加 new 會產生 CS0108 警告)
    public new void Show() => Console.WriteLine("Derived.Show");

    // 2. 隱藏非虛擬方法(同樣建議加 new 消除警告)
    public new void Print() => Console.WriteLine("Derived.Print");
}

行為驗證

Base b = new Derived();
b.Show();  // 輸出:Base.Show  (虛擬方法走多型,呼叫基底實作)
b.Print(); // 輸出:Base.Print(非虛擬方法靜態繫結,呼叫基底實作)

Derived d = new Derived();
d.Show();  // 輸出:Derived.Show
d.Print(); // 輸出:Derived.Print

關鍵區別:new vs override

特性new (隱藏)override (覆寫)
基底成員需標記不需要必須 virtual/abstract/override
多型行為無(靜態繫結)有(動態派發)
適用目標任何成員(方法、屬性、欄位、事件)僅虛擬/抽象方法、屬性、索引子、事件
版本控制意圖「我要取代這個成員,基底版本不再相關」「我要延伸/修改基底行為」

常見陷阱

  • 以為 new 能改變基底類別行為 → 錯誤,基底類別程式碼完全不受影響。
  • 在介面實作中使用 new 隱藏介面成員 → 會導致介面呼叫時仍執行介面預設實作,極易產生 Bug。

用法三:泛型約束——要求型別擁有公用無參建構函式

// 僅允許擁有 public 無參建構函式的具象類別
public class Repository where T : class, new()
{
    public T Create() => new T(); // 編譯器保證 T 可被 new()
}

// 使用範例
var repo = new Repository(); // User 必須有 public User() {}
var user = repo.Create();

組合約束順序規則

where T : class, new()           // 參考型別 + 無參建構函式
where T : struct, new()          // 實值型別(結構體隱含無參建構函式,new() 多餘但合法)
where T : IEntity, new()         // 介面 + 無參建構函式
where T : BaseClass, new()       // 基底類別 + 無參建構函式
where T : notnull, new()         // 非 nullable 型別 + 無參建構函式 (C# 8.0+)

約束順序固定:class/struct/notnull → 基底類別 → 介面 → new()。

實戰決策指南

情境建議
建立物件實例直接使用 new Type(),優先考慮工廠模式/依賴注入解耦
衍生類別想「完全取代」基底非虛擬成員加 new 修飾詞並加上 XML 註解說明隱藏意圖
衍生類別想「擴充」基底虛擬成員基底加 virtual,衍生加 override
泛型工廠/容器需實例化 T加 where T : new(),並文件化「T 必須有公用無參建構函式」
介面預設實作想被具體類別取代不要用 new,改用顯式介面實作或重新設計介面

總結

  • 運算子 new:配置記憶體、呼叫建構函式,C# 物件誕生的起點。
  • 修飾詞 new:刻意切斷多型鏈結,隱藏基底同名成員,屬於「版本控制」工具,慎用並明確文件化。
  • 約束 new():泛型程式設計的安全網,讓編譯器保證「可被實例化」,支援工廠模式、物件池等通用元件。

搞懂三者差異,才能在程式碼審查時精準溝通意圖,避免「以為覆寫其實隱藏」等低級錯誤。

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