C#中Activator的具體使用
Activator 是 C# 中用于動態(tài)創(chuàng)建對象實(shí)例的核心類,位于 System 命名空間。它通過**反射(Reflection)**機(jī)制,在運(yùn)行時根據(jù)類型信息創(chuàng)建對象,而無需在編譯時知道具體類型。
?? 一、Activator的核心作用
- 在不知道具體類型的情況下創(chuàng)建實(shí)例(如 IoC 容器、插件系統(tǒng)、序列化框架等)。
- 支持帶參數(shù)或無參的構(gòu)造函數(shù)調(diào)用。
- 可創(chuàng)建值類型和引用類型。
- 是依賴注入(DI)、ORM、MVC 框架等底層常用工具。
?? 二、常用方法詳解
1.Activator.CreateInstance(Type type)
調(diào)用類型的無參構(gòu)造函數(shù)創(chuàng)建實(shí)例。
Type type = typeof(List<string>); object instance = Activator.CreateInstance(type); // 等價于:new List<string>();
? 要求:類型必須有 public 無參構(gòu)造函數(shù),否則拋出 MissingMethodException。
2.Activator.CreateInstance(Type type, params object[] args)
調(diào)用匹配參數(shù)的構(gòu)造函數(shù)創(chuàng)建實(shí)例。
Type type = typeof(Dictionary<string, int>); object dict = Activator.CreateInstance(type, 10); // 調(diào)用 Dictionary(int capacity)
?? 匹配規(guī)則:
- 按參數(shù)數(shù)量和類型精確匹配(不支持隱式轉(zhuǎn)換,如
int→long會失?。?。 - 如果多個構(gòu)造函數(shù)匹配,行為未定義(通常選第一個,但不可靠)。
?? 注意:參數(shù)必須按構(gòu)造函數(shù)聲明順序傳入。
3. 泛型版本:Activator.CreateInstance<T>()
編譯時已知類型,但仍用反射創(chuàng)建(性能略低于 new T())。
List<string> list = Activator.CreateInstance<List<string>>();
? 要求:T 必須有 public 無參構(gòu)造函數(shù)(受 where T : new() 約束)。
4. 創(chuàng)建非 public 或內(nèi)部類型(需 BindingFlags)
// 假設(shè) MyClass 有一個 internal 構(gòu)造函數(shù)
Type type = typeof(MyClass);
var instance = Activator.CreateInstance(
type,
BindingFlags.NonPublic | BindingFlags.Instance,
null,
new object[] { "param" },
null
);
適用于測試私有構(gòu)造函數(shù)或訪問內(nèi)部類型(需注意安全性)。
5. 創(chuàng)建數(shù)組、委托、指針等特殊類型
// 創(chuàng)建長度為 5 的 string 數(shù)組 Array arr = (Array)Activator.CreateInstance(typeof(string[]), 5); // 創(chuàng)建多維數(shù)組 Array matrix = Array.CreateInstance(typeof(int), 3, 4); // 更推薦用 Array.CreateInstance
?? 三、底層原理(簡要)
Activator.CreateInstance 內(nèi)部使用:
- 反射(
ConstructorInfo.Invoke) - 在 .NET Core / .NET 5+ 中,對常見場景做了優(yōu)化(如緩存委托)
- 但仍比
new慢 10~100 倍(見下文性能)
?? 四、性能問題與替代方案
?Activator.CreateInstance性能較差
- 每次調(diào)用都涉及反射、參數(shù)校驗(yàn)、安全檢查。
- 不適合高頻調(diào)用(如循環(huán)內(nèi))。
? 高性能替代方案
方案 1:使用System.Linq.Expressions編譯表達(dá)式樹
var constructor = typeof(MyClass).GetConstructor(new Type[] { typeof(string) });
var param = Expression.Parameter(typeof(object[]));
var argsExp = constructor.GetParameters().Select((p, i) =>
Expression.Convert(Expression.ArrayIndex(param, Expression.Constant(i)), p.ParameterType)
).ToArray();
var newExp = Expression.New(constructor, argsExp);
var lambda = Expression.Lambda<Func<object[], object>>(newExp, param);
var factory = lambda.Compile();
// 使用
object instance = factory(new object[] { "hello" });
方案 2:使用System.Reflection.Emit(更復(fù)雜,性能最高)
適用于框架開發(fā)(如 DI 容器)。
方案 3:.NET 7+ 推薦:RuntimeHelpers.GetUninitializedObject(僅限無參、跳過構(gòu)造函數(shù))
object obj = RuntimeHelpers.GetUninitializedObject(typeof(MyClass)); // ?? 危險!不調(diào)用構(gòu)造函數(shù),字段為默認(rèn)值
方案 4:泛型約束 +new()
public T CreateInstance<T>() where T : new()
{
return new T(); // 零反射,最快!
}
?? 五、常見陷阱與注意事項(xiàng)
| 問題 | 說明 |
|---|---|
| 無參構(gòu)造函數(shù)缺失 | 拋出 MissingMethodException |
| 參數(shù)類型不匹配 | 拋出 ArgumentException |
| 私有構(gòu)造函數(shù) | 默認(rèn)無法調(diào)用,需 BindingFlags.NonPublic |
| 值類型處理 | Activator.CreateInstance(typeof(int)) 返回 0(合法) |
| 抽象類/接口 | 不能直接創(chuàng)建,會拋異常 |
| 線程安全 | CreateInstance 本身線程安全,但創(chuàng)建的對象不一定 |
? 六、典型應(yīng)用場景
IoC/DI 容器
object instance = Activator.CreateInstance(implementationType, dependencies);
插件系統(tǒng)(加載外部 DLL)
Assembly asm = Assembly.LoadFrom("Plugin.dll"); Type pluginType = asm.GetType("MyPlugin"); IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType);ORM 實(shí)體實(shí)例化
(如 Entity Framework 動態(tài)創(chuàng)建實(shí)體對象)單元測試中 Mock 對象創(chuàng)建
泛型工廠模式
public T Create<T>() => Activator.CreateInstance<T>();
?? 總結(jié)
| 特性 | 說明 |
|---|---|
| 用途 | 運(yùn)行時動態(tài)創(chuàng)建對象 |
| 核心方法 | CreateInstance(Type, args) |
| 優(yōu)點(diǎn) | 靈活,支持任意類型 |
| 缺點(diǎn) | 性能低,易出錯 |
| 最佳實(shí)踐 | 僅用于低頻場景;高頻場景用表達(dá)式樹或泛型約束 |
?? 建議:在寫 DI 容器、框架或插件系統(tǒng)時,初期可用 Activator 快速驗(yàn)證邏輯,后期替換為高性能方案。
到此這篇關(guān)于C#中Activator的具體使用的文章就介紹到這了,更多相關(guān)C# Activator內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C#中序列化實(shí)現(xiàn)深拷貝,實(shí)現(xiàn)DataGridView初始化刷新的方法
下面小編就為大家?guī)硪黄狢#中序列化實(shí)現(xiàn)深拷貝,實(shí)現(xiàn)DataGridView初始化刷新的方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-02-02
老生常談C#?中的?StreamReader?和?StreamWriter?類
這篇文章主要介紹了老生常談C#?中的?StreamReader?和?StreamWriter?類,StreamReader?和?StreamWriter?位于?System.IO?命名空間中,當(dāng)您想要讀取或?qū)懭牖谧址臄?shù)據(jù)時,這兩個類都很有用,需要的朋友可以參考下2024-06-06
UnityWebRequest前后端交互實(shí)現(xiàn)過程解析
這篇文章主要介紹了UnityWebRequest前后端交互實(shí)現(xiàn)過程解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2020-06-06
C# PictureBox圖片控件實(shí)現(xiàn)圖片交換
在c#中可以使用PictureBox控件來呈現(xiàn)圖像,本文主要介紹了C# PictureBox實(shí)現(xiàn)圖片交換,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-06-06
C# 字符串string和內(nèi)存流MemoryStream及比特數(shù)組byte[]之間相互轉(zhuǎn)換
本文主要介紹字符串string和內(nèi)存流MemoryStream及比特數(shù)組byte[]之間相互轉(zhuǎn)換的方法,需要的小伙伴可以參考一下。2016-05-05
c#實(shí)現(xiàn)網(wǎng)頁圖片提取工具代碼分享
c#實(shí)現(xiàn)網(wǎng)頁圖片提取工具代碼分享,大家參考使用吧2013-12-12

