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

C# 泛型 new() 約束深度解析:編譯期檢查 vs 執行期 Activator.CreateInstance

     編輯:關於C#

常見誤解

許多開發者以為 where T : new() 讓泛型內部 new T() 像非泛型一樣直接呼叫建構函式。**實際上:編譯器產生的 IL 仍呼叫 Activator.CreateInstance<T>() (反射機制)。**

編譯器做了什麼?

  1. 編譯期檢查:驗證型別引數 T 擁有 公用無參數建構函式。若無,編譯錯誤 CS0310/CS0311。
  2. 產生 IL:new T() 編譯為 call System.Activator::CreateInstance<!!T>()。

IL 對比驗證


// 原始碼
public class Factory where T : new()
{
    public T Create() => new T();
}

// 編譯後 IL (簡化)
.method public hidebysig instance !!T Create() cil managed
{
    .maxstack 1
    L_0000: call !!0 [System.Runtime]System.Activator::CreateInstance<!!T>()
    L_0005: ret
}

// 對比:非泛型 new()
.method public hidebysig instance class MyClass CreateNonGeneric() cil managed
{
    .maxstack 1
    L_0000: newobj instance void MyClass::.ctor()  // 直接呼叫建構函式
    L_0005: ret
}

效能影響

方式機制相對速度備註
new T() (有 new() 約束)Activator.CreateInstance (反射 + 快取)~10-50x 慢於直接 new首次呼叫較慢,後續透過委派快取加速
new ConcreteType()直接 newobj IL 指令基準 (最快)
Activator.CreateInstance<T>() 手動呼叫相同相同
編譯表達式樹 Expression.New 快取委派動態編譯委派接近直接 new高頻建立場景優選

高頻建立優化方案


using System;
using System.Linq.Expressions;

public static class FastActivator where T : new()
{
    // 靜態建構子僅執行一次,編譯 Lambda 為強型別委派
    private static readonly Func Creator = CreateCreator();

    private static Func CreateCreator()
    {
        var newExpr = Expression.New(typeof(T).GetConstructor(Type.EmptyTypes)!);
        return Expression.Lambda>(newExpr).Compile();
    }

    public static T CreateInstance() => Creator();
}

// 使用
var instance = FastActivator.CreateInstance(); // 極快,無反射開銷

new() 約束進階規則

  • 僅限公用無參數建構函式:`private`、`protected`、`internal` 或帶參數建構函式皆不符合。
  • 結構體預設滿足:`struct` 隱含無參數建構函式 (預設值),但 `where T : struct` 已包含此語意,無需額外加 `new()`。
  • 介面無法約束建構函式:介面不包含建構函式定義。
  • 抽象類別不可用:無法實例化,編譯錯誤。
  • 多重約束順序:`where T : class, IInterface, new()` (參考型別 → 介面 → 建構函式)。

實務決策指南

場景建議方案
低頻建立 (工廠、Plugin 載入)直接 new T() + where T : new(),簡潔優先
高頻建立 (物件池、每幀實例化)FastActivator<T> 編譯表達式樹快取委派
需傳參數建構改用 Func<TArg, T> 工廠委派注入,移除 new() 約束
結構體高效能建立default(T) 或 new T() (結構體無反射開銷)

結論

where T : new() 是**編譯期語法糖**,提供型別安全保證,但執行期仍透過反射建立實例。理解此機制有助於在效能敏感場合做出正確優化選擇。

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