C# dynamic類型使用詳解
簡介
C# 中的 dynamic 是一種特殊類型,它允許在運行時確定對象的類型和成員,而不是在編譯時。
dynamic 的定義
dynamic是一種類型,它告訴編譯器對其進行“動態(tài)類型解析”。dynamic類型的變量會跳過編譯時類型檢查,所有的操作會推遲到運行時進行。- 適合處理未知類型的對象,或需要與動態(tài)語言(如
Python、JavaScript)互操作的場景。
dynamic 的使用
動態(tài)類型賦值
dynamic obj = 10; // 可以是整數(shù)
obj = "Hello"; // 可以變成字符串
obj = new { Name = "John", Age = 30 }; // 也可以是匿名類型訪問成員
動態(tài)對象的成員在運行時解析,因此可以訪問任意成員:
如果訪問了不存在的成員,運行時會拋出 RuntimeBinderException。
dynamic obj = new { Name = "John", Age = 30 };
Console.WriteLine(obj.Name); // 輸出: John動態(tài)方法調用
dynamic math = new { Add = (Func<int, int, int>)((x, y) => x + y) };
Console.WriteLine(math.Add(2, 3)); // 輸出: 5dynamic 的核心特性
與編譯時類型(靜態(tài)類型)的區(qū)別:
- 編譯時檢查:
dynamic不會在編譯時檢查類型或成員是否存在,所有操作推遲到運行時。 - 靜態(tài)類型:
object和其他類型在編譯時進行類型檢查。
object obj1 = 10; // obj1.SomeMethod(); // 編譯錯誤:object 沒有 SomeMethod 方法 dynamic obj2 = 10; // obj2.SomeMethod(); // 編譯通過,但運行時拋出異常
類型推斷
動態(tài)類型在運行時確定,而靜態(tài)類型通過編譯器推斷:
dynamic dynamicVariable = 123; // 編譯器不檢查類型 int staticVariable = 123; // 編譯器推斷為 int object obj = "Hello"; // Console.WriteLine(obj.Length); // 編譯錯誤 Console.WriteLine(((string)obj).Length); // 強制轉換 dynamic dyn = "Hello"; Console.WriteLine(dyn.Length); // 運行時解析,編譯通過
使用場景
- 與動態(tài)語言交互:調用動態(tài)語言的
API,如COM對象、IronPython等 JSON或XML數(shù)據(jù)處理:在處理結構未知的數(shù)據(jù)時動態(tài)解析。- 匿名類型和動態(tài)擴展:快速訪問動態(tài)創(chuàng)建的對象。
注意事項
- 性能開銷:動態(tài)綁定會引入性能開銷,因為解析是在運行時完成的。
- 類型安全:缺乏編譯時類型檢查,可能導致運行時錯誤。
- 調試困難:錯誤可能難以發(fā)現(xiàn),尤其是在復雜場景中。
ExpandoObject 與 dynamic
ExpandoObject 是一個動態(tài)對象,可在運行時動態(tài)添加或刪除成員:
常用于需要靈活擴展的場景,如 JSON 數(shù)據(jù)的解析
using System.Dynamic;
dynamic expando = new ExpandoObject();
expando.Name = "John";
expando.Age = 30;
Console.WriteLine($"{expando.Name}, {expando.Age}");ExpandoObject 內部實現(xiàn)機制
ExpandoObject 實現(xiàn)了以下關鍵接口:
IDynamicMetaObjectProvider:提供動態(tài)行為(如動態(tài)調用、成員訪問)的核心接口。IDictionary<string, object>:內部使用一個 Dictionary<string, object>存儲動態(tài)添加的成員。
using System.Dynamic; dynamic expando = new ExpandoObject(); expando.Name = "John"; // 動態(tài)添加成員 Console.WriteLine(expando.Name); // 動態(tài)訪問成員 // 等價于: var expando = new ExpandoObject() as IDictionary<string, object>; expando["Name"] = "John"; Console.WriteLine(expando["Name"]);
ExpandoObject 如何實現(xiàn)動態(tài)性?
ExpandoObject 使用動態(tài)綁定和元對象來實現(xiàn)動態(tài)行為:
- 動態(tài)綁定:通過
IDynamicMetaObjectProvider,在運行時解析屬性、方法等訪問請求。 - 內部字典:通過
Dictionary<string, object>存儲成員。 - 元對象:
ExpandoObject的動態(tài)行為由一個元對象ExpandoMetaObject提供支持,它負責解釋動態(tài)操作并將其映射到內部字典。
ExpandoObject 線程安全性
ExpandoObject本質上不是線程安全的,因為它允許動態(tài)修改成員。- 在多線程場景下,需要通過顯式鎖定來確保線程安全。
ExpandoObject 使用示例
- 動態(tài)添加/刪除成員
dynamic expando = new ExpandoObject();
expando.Name = "John";
expando.Age = 30;
// 刪除成員
var dict = (IDictionary<string, object>)expando;
dict.Remove("Age");
// 檢查成員
Console.WriteLine(dict.ContainsKey("Name")); // True
Console.WriteLine(dict.ContainsKey("Age")); // False- 結合
LINQ查詢
因為 ExpandoObject 實現(xiàn)了 IDictionary<string, object>,可以結合 LINQ 操作:
dynamic expando = new ExpandoObject();
expando.Name = "John";
expando.Age = 30;
var dict = (IDictionary<string, object>)expando;
var filtered = dict.Where(kv => kv.Key.StartsWith("N"));
foreach (var kv in filtered)
{
Console.WriteLine($"{kv.Key}: {kv.Value}");
}綜合考慮
1.使用 dynamic 的場景:
- 與外部動態(tài)類型(如
COM、動態(tài)語言)交互。 - 動態(tài)調用方法或訪問屬性,無需構建明確的對象。
- 臨時需要動態(tài)行為,但不需要動態(tài)修改成員。
2.使用 ExpandoObject 的場景:
- 需要構建動態(tài)擴展的對象。
- 動態(tài)添加和刪除屬性。
- 構建輕量級、靈活的業(yè)務模型。
選擇建議
| 特性 | dynamic | ExpandoObject |
|---|---|---|
| 動態(tài)成員解析 | 支持任意動態(tài)成員,解析時運行時檢查 | 只能操作明確添加到對象的動態(tài)成員 |
| 動態(tài)成員添加/刪除 | 不支持 | 支持(通過字典實現(xiàn)) |
| 類型檢查 | 編譯時無類型檢查,運行時解析 | 同樣運行時解析 |
| 適合的場景 | 動態(tài)語言互操作、臨時操作、反射 | 動態(tài)構建對象、領域模型擴展 |
| 性能 | 比靜態(tài)類型慢,因為運行時動態(tài)綁定 | 更高效,基于字典實現(xiàn) |
| 實現(xiàn)復雜度 | 動態(tài)行為由 CLR 處理 | 由 ExpandoObject 自行實現(xiàn)動態(tài)行為 |
| 對字典的支持 | 不支持 | 內部就是 IDictionary<string, object> |
| 安全性 | 運行時錯誤較多,調試復雜 | 動態(tài)但有一定約束 |
總結
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
C#創(chuàng)建簡單windows窗體應用(加法器)
這篇文章主要為大家詳細介紹了C#創(chuàng)建一個簡單windows窗體應用的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2019-03-03
C#(asp.net)多線程用法示例(可用于同時處理多個任務)
這篇文章主要介紹了C#(asp.net)多線程Thread用法,可用于同時處理多個任務,以簡單數(shù)學運算為例講述了Thread類實現(xiàn)多線程的相關技巧,需要的朋友可以參考下2016-06-06
Unity游戲開發(fā)中的中介者模式的應用與實現(xiàn)
中介者模式是Unity游戲開發(fā)中常用的設計模式之一,用于減少對象之間的直接耦合,通過引入中介者來協(xié)調對象之間的交互。通過中介者模式,游戲對象可以更加靈活地進行交互和協(xié)同工作,降低系統(tǒng)復雜度,使代碼更加易于維護和擴展2023-05-05

