📅 Day 21:動態類型與動態語言運行時(Dynamic Types & DLR)
? 學習目標:
- 理解什么是
dynamic
類型; - 掌握
dynamic
與object
的區別; - 理解 DLR(Dynamic Language Runtime) 的作用;
- 學會使用
dynamic
簡化反射、COM 互操作等場景; - 理解
ExpandoObject
和DynamicObject
的用法; - 編寫一個基于
dynamic
的 JSON 解析器或腳本執行器示例。
🧠 一、什么是 dynamic
類型?
在 C# 中,dynamic
是一種特殊的類型,它繞過了編譯時的類型檢查,將類型解析延遲到運行時進行。
示例:
dynamic x = 10;
x = "Hello"; // 合法
x = new Person(); // 合法
?? 編譯時不檢查成員是否存在,運行時才會拋出異常。
🔁 二、dynamic
vs object
特性 | object | dynamic |
---|---|---|
編譯時類型檢查 | ? | ? |
運行時解析 | ? | ? |
性能 | 更快 | 稍慢(需 DLR 解析) |
適合場景 | 多態、泛型 | 反射簡化、腳本交互 |
💡 三、DLR(Dynamic Language Runtime)
DLR(動態語言運行時) 是 .NET Framework 4 引入的一個子系統,用于支持動態語言(如 Python、Ruby)在 .NET 平臺上的運行。它也支撐了 C# 中的 dynamic
功能。
DLR 的核心功能包括:
- 運行時綁定(Runtime Binding)
- 動態對象解析(如 COM 對象、Python 對象)
- 緩存機制優化性能
🧩 四、常見使用場景
場景 1:簡化反射調用
傳統反射方式:
object obj = GetSomeObject();
MethodInfo method = obj.GetType().GetMethod("DoWork");
method.Invoke(obj, null);
使用 dynamic
:
dynamic obj = GetSomeObject();
obj.DoWork(); // 編譯不報錯,運行時自動解析
場景 2:COM 互操作(如 Excel 自動化)
Type excelType = Type.GetTypeFromProgID("Excel.Application");
dynamic excel = Activator.CreateInstance(excelType);
excel.Visible = true;
excel.Workbooks.Add();
場景 3:處理不確定結構的數據(如 JSON)
string json = "{\"Name\":\"張三\",\"Age\":25}";
dynamic data = JsonSerializer.Deserialize<JsonElement>(json);Console.WriteLine(data.Name);
Console.WriteLine(data.Age);
🧱 五、System.Dynamic
命名空間
C# 提供了幾個類來幫助你創建自定義的動態對象:
1. ExpandoObject
表示一個可以在運行時動態添加和刪除成員的對象。
dynamic person = new ExpandoObject();
person.Name = "李四";
person.Age = 30;person.SayHello = new Action(() => Console.WriteLine("你好!"));person.SayHello(); // 輸出:你好!
2. DynamicObject
你可以繼承此類并重寫其方法來自定義動態行為。
public class MyDynamic : DynamicObject
{private Dictionary<string, object> _properties = new();public override bool TrySetMember(SetMemberBinder binder, object value){_properties[binder.Name] = value;return true;}public override bool TryGetMember(GetMemberBinder binder, out object result){return _properties.TryGetValue(binder.Name, out result);}
}// 使用
dynamic obj = new MyDynamic();
obj.Name = "王五";
Console.WriteLine(obj.Name); // 輸出:王五
🧪 六、動態表達式樹(Expression Trees)
雖然 dynamic
很方便,但如果你需要高性能的動態行為,推薦使用 Expression<TDelegate>
構建動態委托。
ParameterExpression param = Expression.Parameter(typeof(int), "x");
Expression body = Expression.Multiply(param, param);
Func<int, int> square = Expression.Lambda<Func<int, int>>(body, param).Compile();Console.WriteLine(square(5)); // 輸出:25
💪 實戰練習:構建一個簡單的動態 JSON 解析器
功能要求:
- 從 API 獲取 JSON 數據;
- 使用
dynamic
解析并輸出字段; - 支持嵌套屬性訪問。
示例代碼:
using System;
using System.Net.Http;
using System.Text.Json;class Program
{static async Task Main(){using HttpClient client = new HttpClient();string json = await client.GetStringAsync("https://jsonplaceholder.typicode.com/users/1");dynamic user = JsonSerializer.Deserialize<JsonElement>(json);Console.WriteLine("用戶ID:" + user.id);Console.WriteLine("用戶名:" + user.username);Console.WriteLine("地址城市:" + user.address.city);}
}
?? 七、注意事項與最佳實踐
建議 | 說明 |
---|---|
避免濫用 dynamic | 它犧牲了編譯時安全性和 IDE 智能提示 |
不要用于公共 API | 應該優先使用接口或泛型 |
謹慎用于性能關鍵路徑 | DLR 有額外開銷 |
在反射、JSON、COM 場景中合理使用 | 可顯著提升開發效率 |
📝 小結
今天你學會了:
dynamic
類型的基本概念及其與object
的區別;- 了解了 DLR(動態語言運行時) 的作用;
- 掌握了如何使用
dynamic
簡化反射、COM 互操作、JSON 解析等場景; - 學會使用
ExpandoObject
和DynamicObject
創建自定義動態對象; - 編寫了一個基于
dynamic
的 JSON 解析器示例; - 了解了
dynamic
的性能影響及適用場景。
dynamic
是 C# 中非常強大的工具,尤其適用于與外部系統交互、快速原型開發等場景。但在大型項目中應謹慎使用以確保可維護性。
🧩 下一步學習方向(Day 22)
明天我們將進入一個新的主題 —— LINQ(Language Integrated Query)基礎與進階,你將學會如何使用 LINQ 查詢集合、數據庫、XML,并掌握查詢語法與方法語法的區別。