📅 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,并掌握查询语法与方法语法的区别。