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

C# 泛型 new() 約束深度解析:背後使用 Activator.CreateInstance

     編輯:關於C語言

常見誤解

許多開發者以為 where T : new() 讓 new T() 在編譯期產生與具象型別完全相同的 IL 指令。實際上並非如此。

編譯器真正做的事

  1. 靜態檢查:在泛型實例化處 (如 new MyClass<SomeType>()) 驗證 SomeType 是否有**公用無參數建構函式**。否則編譯錯誤 (CS0310)。
  2. 產生 IL:new T() 編譯為 call !!0 [mscorlib]System.Activator::CreateInstance<!!0>(),即**透過反射在執行期建立實例**。

IL 對照 (簡化)

.method public hidebysig specialname rtspecialname 
        instance void  .ctor() cil managed
{
  // 程式碼大小       15 (0xf)
  .maxstack  1
  IL_0000:  ldarg.0
  IL_0001:  call       instance void [mscorlib]System.Object::.ctor()
  IL_0006:  ldarg.0
  IL_0007:  call       !!0 [mscorlib]System.Activator::CreateInstance<T>()
  IL_000c:  stfld      class T MyClass`1<T>::t
  IL_0011:  ret
}

效能影響

  • Activator.CreateInstance<T>() 涉及反射,比直接 new SomeType() **慢 10~100 倍** (視 .NET 版本與 JIT 優化)。
  • .NET Core / .NET 5+ 對泛型實例化有顯著優化 (內建快取委派),但仍比直接 new 慢。

高效能替代方案

1. 委派快取 (推薦)

public class Factory<T> where T : new()
{
    private static readonly Func<T> _creator = CreateCreator();

    private static Func<T> CreateCreator()
    {
        // 運算式樹編譯為強型別委派,僅第一次呼叫付出反射成本
        var ctor = typeof(T).GetConstructor(Type.EmptyTypes);
        var lambda = Expression.Lambda>(Expression.New(ctor));
        return lambda.Compile();
    }

    public static T Create() => _creator();
}

2. 介面約束 + 抽象工廠


public interface IFactory { T Create(); }

public class MyService where T : new()
{
    private readonly IFactory _factory;
    public MyService(IFactory factory) { _factory = factory; }
    public T CreateInstance() => _factory.Create();
}

// 註冊具象工廠 (DI 容器自動解析)
public class ConcreteFactory : IFactory 
{ 
    public ConcreteType Create() => new ConcreteType(); // 直接 new,零反射
}

3. .NET 6+ default 建構函式語法 (僅結構體)


struct Point { public int X, Y; }
Point p = new(); // 隱含 new(),結構體無反射開銷

何時仍可接受 new() 約束?

  • 物件建立頻率低 (如啟動時單例、設定物件)。
  • 原型模式:T prototype = new T(); 後續用 MemberwiseClone 複製。
  • 測試代碼、原型驗證、教學範例。

總結

where T : new() 是**編譯期約束 + 執行期反射建立**的語法糖。高效能場景請改用**委派快取**、**抽象工廠**或 **DI 容器**注入具象工廠,避免熱路徑反射開銷。

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