主页 > 创业  > 

C#dynamic关键字使用详解

C#dynamic关键字使用详解
总目录
前言

dynamic 是 C# 4.0 引入的关键字,用于声明动态类型,允许在运行时解析类型和成员,而非编译时。它主要设计用于简化与动态语言(如 Python、JavaScript)的交互、处理未知结构的数据(如 JSON、XML)以及减少反射代码的复杂性。


一、基本概念 动态类型解析:编译器不会对 dynamic 变量进行类型检查,所有操作(方法调用、属性访问)在运行时解析。底层机制:由 DLR(Dynamic Language Runtime)驱动,使用 IDynamicMetaObjectProvider 接口适用场景: 与动态语言(IronPython、JavaScript)交互。处理未知结构的动态数据(如反序列化 JSON)。简化反射代码。COM 互操作(如操作 Excel 对象模型)。 性能代价:动态类型解析比静态类型慢,需谨慎使用高频代码。 二、基本用法 1. 动态类型申明 dynamic value = "Hello World"; Console.WriteLine(value.GetType()); // 输出: System.String value = 42; // 动态变量可重新赋值为任意类型 Console.WriteLine(value.GetType()); // 输出: System.Int32 value = "Hello"; // 运行时切换为 string Console.WriteLine(value.Length); // 输出 5 value = new List<int> { 1, 2, 3 }; value.Add(4); // 运行时调用 Add 方法 dynamic person = new { Name = "John", Age = 30 }; Console.WriteLine(person.Name); // 输出: John 2. 调用未知方法或属性 dynamic obj = new ExpandoObject(); obj.Name = "Alice"; // 动态添加属性 obj.Print = new Action(() => Console.WriteLine(obj.Name)); obj.Print(); // 输出: Alice 3. 动态方法调用 public class Calculator { public int Add(int a, int b) => a + b; } class Program { static void Main() { dynamic calc = new Calculator(); int result = calc.Add(3, 4); // 编译时不检查方法是否存在 Console.WriteLine(result); // 输出: 7 } } 三、dynamic vs object vs var 特性dynamicobjectvar类型检查时机运行时编译时编译时(类型推断)成员访问动态解析需要强制转换静态类型访问性能较慢需要拆箱最优使用场景动态交互通用对象容器类型声明简化智能提示支持无有有代码灵活性高(适应未知结构)低(需明确类型)适中 四、应用场景 1. 动态类型与反射

动态类型可简化反射操作,但需权衡性能与可读性:

反射实现

object obj = Activator.CreateInstance(typeof(MyClass)); MethodInfo method = typeof(MyClass).GetMethod("MyMethod"); method.Invoke(obj, new object[] { 42 });

动态类型实现

dynamic obj = Activator.CreateInstance(typeof(MyClass)); obj.MyMethod(42); // 代码更简洁 // 传统反射方式 object obj = Activator.CreateInstance(typeof(MyClass)); MethodInfo method = obj.GetType().GetMethod("DoWork"); method.Invoke(obj, null); // 使用 dynamic 简化 dynamic dynObj = Activator.CreateInstance(typeof(MyClass)); dynObj.DoWork(); // 直接调用方法 2. 动态对象(ExpandoObject 和 DynamicObject) 1. ExpandoObject

允许动态添加属性和方法:

static void Main() { dynamic person = new ExpandoObject(); person.Name = "Bob"; person.Age = 25; person.SayHello = (Action)(() => Console.WriteLine($"Hi, I'm {person.Name}")); person.SayHello(); // 输出 "Hi, I'm Bob" // 转换为字典 var dict = (IDictionary<string, object>)person; Console.WriteLine(dict["Name"]); // 输出 Bob Console.WriteLine(dict["Age"]); // 输出 25 Action action= (Action)dict["SayHello"]; action?.Invoke(); //输出 "Hi, I'm Bob" } 2. 自定义 DynamicObject

实现动态行为控制:

public class DynamicDictionary : DynamicObject { private Dictionary<string, object> _dict = new Dictionary<string, object>(); public override bool TryGetMember(GetMemberBinder binder, out object result) { return _dict.TryGetValue(binder.Name, out result); } public override bool TrySetMember(SetMemberBinder binder, object value) { _dict[binder.Name] = value; return true; } } class Program { static void Main() { dynamic dict = new DynamicDictionary(); dict.City = "Shanghai"; Console.WriteLine(dict.City); // 输出: Shanghai } }
3. 处理动态数据(JSON 示例)

使用 Newtonsoft.Json(或 System.Text.Json)处理动态 JSON:

static void Main() { string json= """{ "Name": "Alice", "Age": 30 }"""; dynamic data = JObject.Parse(json); //或使用下面的方式 //dynamic data = JsonConvert.DeserializeObject<dynamic>(json); Console.WriteLine(data.Name); // 输出 Alice Console.WriteLine(data.Age + 5); // 输出 35 // 动态扩展属性 data.Country = "USA"; // 运行时添加新属性 Console.WriteLine(data.Country);// 输出 USA } 4. COM 互操作(Excel 自动化) Type excelType = Type.GetTypeFromProgID("Excel.Application"); dynamic excel = Activator.CreateInstance(excelType); excel.Visible = true; // 设置属性 dynamic workbook = excel.Workbooks.Add(); dynamic worksheet = workbook.ActiveSheet; worksheet.Cells[1, 1] = "Hello World"; // 动态访问单元格 五、注意事项与最佳实践 1. 注意事项 避免过度使用: 优先使用静态类型确保安全性和性能。仅在必要时(如处理动态数据、COM 互操作)使用 dynamic。 无智能提示: 成员解析完全在运行时完成 错误处理: 动态调用可能抛出 RuntimeBinderException,需捕获异常。错误延迟:类型错误在运行时才会暴露 try { dynamic obj = new object(); obj.InvalidMethod(); } catch (RuntimeBinderException ex) { Console.WriteLine($"运行时错误: {ex.Message}"); } 2. 最佳实践 性能优化: 缓存频繁使用的动态操作结果。在循环或高频代码中避免使用 dynamic。 // 缓存高频操作(减少动态解析次数) dynamic obj = GetDynamicObject(); var cachedAction = (Action)obj.DoWork; // 转换为委托 for(int i=0; i<1000; i++) { cachedAction(); // 比直接调用 obj.DoWork() 更快 } 严格限制使用范围:仅在必需时使用 泛型与接口:通过设计模式避免动态类型。 配合 try-catch:处理可能的运行时异常单元测试覆盖:针对动态代码增加测试用例优先选择替代方案: 对于已知结构:使用强类型类对于 JSON:推荐 System.Text.Json 的强类型反序列化对于反射:考虑 generic 或 delegate 优化
结语

回到目录页:C#/.NET 知识汇总 希望以上内容可以帮助到大家,如文中有不对之处,还请批评指正。

标签:

C#dynamic关键字使用详解由讯客互联创业栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“C#dynamic关键字使用详解