当前位置: 首页 > article >正文

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.Stringvalue = 42;                        // 动态变量可重新赋值为任意类型
Console.WriteLine(value.GetType()); // 输出: System.Int32value = "Hello";                   // 运行时切换为 string
Console.WriteLine(value.Length);  // 输出 5value = 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. 动态对象(ExpandoObjectDynamicObject

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"]);  // 输出 BobConsole.WriteLine(dict["Age"]);  // 输出 25Action 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);  // 输出 AliceConsole.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 关键字 使用详解

总目录 前言 dynamic 是 C# 4.0 引入的关键字&#xff0c;用于声明动态类型&#xff0c;允许在运行时解析类型和成员&#xff0c;而非编译时。它主要设计用于简化与动态语言&#xff08;如 Python、JavaScript&#xff09;的交互、处理未知结构的数据&#xff08;如 JSON、XML…...

sql server 数据库 锁教程及锁操作

SQL Server数据库 锁的教程 SQL Server 的数据库锁是为了保证数据库的并发性和数据一致性而设计的。锁机制能够确保多个事务不会同时修改同一数据&#xff0c;从而避免数据冲突和不一致的发生。理解 SQL Server 的锁机制对于开发高效、并发性强的数据库应用非常重要。 1. 锁的…...

超全Deepseek资料包,deepseek下载安装部署提示词及本地部署指南介绍

该资料包涵盖了DeepSeek模型的下载、安装、部署以及本地运行的详细指南&#xff0c;适合希望在本地环境中高效运行DeepSeek模型的用户。资料包不仅包括基础的安装步骤&#xff0c;还提供了68G多套独立部署视频教程教程&#xff0c;针对不同硬件配置的模型选择建议&#xff0c;以…...

DeepSeek24小时写作机器人,持续创作高质量文案

内容创作已成为企业、自媒体和创作者的核心竞争力。面对海量的内容需求&#xff0c;人工创作效率低、成本高、质量参差不齐等问题日益凸显。如何在有限时间内产出高质量内容&#xff1f;DeepSeek写作机器人&#xff0c;一款24小时持续创作的智能工具&#xff0c;为企业和个人提…...

用deepseek学大模型08-卷积神经网络(CNN)

yuanbao.tencent.com 从入门到精通卷积神经网络(CNN),着重介绍的目标函数&#xff0c;损失函数&#xff0c;梯度下降 标量和矩阵形式的数学推导&#xff0c;pytorch真实能跑的代码案例以及模型,数据&#xff0c;预测结果的可视化展示&#xff0c; 模型应用场景和优缺点&#xf…...

玩客云 IP查找

1.玩客云使用静态IP在不同网段路由器下不能使用&#xff0c;动态不好找IP地址 1.1使用python3 实现自动获取发送 import requests import os import socket# 从环境变量获取 PushPlus 的 token 和群组编码 PUSH_PLUS_TOKEN os.getenv("PUSH_PLUS_TOKEN") PUSH_PLU…...

【鸿蒙Next】鸿蒙应用发布前的准备

图标生成&#xff1a; https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/ide-apply-generated-icon-V5 debug 与 release使用不同的bundle name 鸿蒙多环境配置 https://segmentfault.com/a/1190000045418731...

【OpenCV】入门教学

&#x1f3e0;大家好&#xff0c;我是Yui_&#x1f4ac; &#x1f351;如果文章知识点有错误的地方&#xff0c;请指正&#xff01;和大家一起学习&#xff0c;一起进步&#x1f440; &#x1f680;如有不懂&#xff0c;可以随时向我提问&#xff0c;我会全力讲解~ &#x1f52…...

嵌入式 lwip http server makefsdata

背景&#xff1a; 基于君正X2000 MCU Freertoslwip架构 实现HTTP server服务&#xff0c;MCU作为HTTP服务器通过网口进行数据包的传输&#xff0c;提供网页服务。其中设计到LWIP提供的工具makefsdata&#xff0c;常用于将文件或目录结构转换为适合嵌入到固件中的二进制格式。 …...

qemu-kvm源码解析-cpu虚拟化

背景 Qemu 虚拟化中&#xff0c;CPU&#xff0c;内存&#xff0c;中断是虚拟化的核心板块。本章主要对CPU虚拟化源码进行分析 而随着技术的发展包括CPU、内存、网卡等常见外设。硬件层面的虚拟化现在已经是云计算的标配。形成了&#xff0c;qemu作为cpu外层控制面&#xff0c…...

【蓝桥杯集训·每日一题2025】 AcWing 6123. 哞叫时间 python

6123. 哞叫时间 Week 1 2月18日 农夫约翰正在试图向埃尔茜描述他最喜欢的 USACO 竞赛&#xff0c;但她很难理解为什么他这么喜欢它。 他说「竞赛中我最喜欢的部分是贝茜说 『现在是哞哞时间』并在整个竞赛中一直哞哞叫」。 埃尔茜仍然不理解&#xff0c;所以农夫约翰将竞赛以…...

数据治理中 大数据处理一般都遵循哪些原则

在数据治理中&#xff0c;大数据处理通常遵循以下原则&#xff1a; 最小化原则&#xff1a;企业应只收集实现特定目的所需的数据&#xff0c;避免数据冗余和安全风险。 合法性原则&#xff1a;企业必须遵守相关法律法规&#xff0c;确保数据处理符合法律要求&#xff0c;降低法…...

Linux 多进程生产者消费者模型实现

Linux 多进程生产者消费者模型实现 一、模型核心组件二、关键代码解析1. 信号量封装类&#xff08;csemp&#xff09;2. 共享内存初始化3. 生产者核心逻辑4. 消费者核心逻辑 三、关键同步机制信号量使用策略操作时序图 四、扩展知识1. System V与POSIX信号量对比2. 共享内存最佳…...

【Python pro】基本数据类型

一、数字类型 1.1 数字类型的组成 1.1.1 整数 &#xff08;1&#xff09;十进制&#xff0c;二进制0b&#xff0c;八进制0o&#xff0c;十六进制0x print(16 0b10000 0o20 0x10) # 输出&#xff1a;True&#xff08;2&#xff09;十进制转其他进制 a bin(16) b oct(1…...

sql server查询IO消耗大的排查sql诊断语句

原文链接&#xff1a; sql server查询IO消耗大的排查sql诊断语句-S3软件[code]select top 50 (total_logical_reads/execution_count) as avg_logical_reads , (total_logical_writes/execution_count) as avg_logical_writes , (tota ... https://blog.s3.sh.cn/thread-120-1…...

Spring Boot 自动装配原理深度剖析

一、引言 在 Java 开发领域&#xff0c;Spring 框架无疑是中流砥柱。而 Spring Boot 的出现&#xff0c;更是极大地简化了 Spring 应用的搭建和开发过程。其中&#xff0c;自动装配原理是 Spring Boot 的核心亮点之一&#xff0c;它让开发者无需手动编写大量繁琐的配置代码&am…...

kubernetes源码分析 kubelet

简介 从官方的架构图中很容易就能找到 kubelet 执行 kubelet -h 看到 kubelet 的功能介绍&#xff1a; kubelet 是每个 Node 节点上都运行的主要“节点代理”。使用如下的一个向 apiserver 注册 Node 节点&#xff1a;主机的 hostname&#xff1b;覆盖 host 的参数&#xff1…...

Golang学习笔记_33——桥接模式

Golang学习笔记_30——建造者模式 Golang学习笔记_31——原型模式 Golang学习笔记_32——适配器模式 文章目录 桥接模式详解一、桥接模式核心概念1. 定义2. 解决的问题3. 核心角色4. 类图 二、桥接模式的特点三、适用场景1. 多维度变化2. 跨平台开发3. 动态切换实现 四、与其他…...

使用EasyExcel和多线程实现高效数据导出

​ 使用EasyExcel和多线程实现高效数据导出 1. 概述 在企业级应用中&#xff0c;数据导出是一个常见的需求。为了提高导出效率&#xff0c;尤其是在处理大量数据时&#xff0c;我们可以结合使用EasyExcel库和多线程技术。本文将详细介绍如何通过EasyExcel和多线程技术实现高…...

告别冷冰冰:如何训练AI写出温暖人心的广告文案

朋友们&#xff0c;你们是不是也好奇过&#xff0c;如果让AI来写广告文案&#xff0c;会是什么效果&#xff1f; 是冷冰冰的数据堆砌&#xff0c;还是也能玩出创意和温度&#xff1f; 别担心&#xff0c;今天我就来给你揭秘&#xff0c;怎么调教AI&#xff0c;让它写出的广告…...

【js逆向_入门】图灵爬虫练习平台 第四题

(base64解码&#xff09;地址&#xff1a;aHR0cHM6Ly9zdHUudHVsaW5ncHl0b24uY24vcHJvYmxlbS1kZXRhaWwvNC8 请求接口带有加密参数&#xff1a; 全局搜索Sign,找到参数生成位置 一目了然&#xff0c;知道参数是怎么构造生成的 调试代码 测试验证思路是否正确 时间&#xff1a; …...

Mybatis后端数据库查询多对多查询解决方案

问题场景&#xff1a; 我开发的是一个论文选择系统。 后端用一个论文表paper来存储论文信息。 论文信息中&#xff0c;包含前置课程&#xff0c;也就是你需要修过这些课程才能选择这个论文。 而一个论文对应的课程有很多个。 这样就造成了一个数据库存储的问题。一个paper…...

记一次 Git Fetch 后切换分支为空的情况

Git Fetch 后切换分支为空的情况 在使用 Git 时&#xff0c;我遇到这样的情况&#xff1a;执行 git fetch 后切换分支&#xff0c;发现工作目录是空的&#xff0c;没有任何文件&#xff0c;所以插眼记录一下。 原因分析 git fetch 的作用&#xff1a;git fetch 只会从远程仓库…...

【MySQL排错 】mysql: command not found 数据库安装后无法加载的解决办法

【MySQL排错 】mysql: command not found 数据库安装后无法加载的解决办法 A Solution to Solve Error - mysql: command not found After The Installation of MySQL Community Server By JacksonML 本文简要介绍如何在macOS安装完毕MySQL数据库服务器后&#xff0c;针对无…...

分享一款AI绘画图片展示和分享的小程序

&#x1f3a8;奇绘图册 【开源】一款帮AI绘画爱好者维护绘图作品的小程序 查看Demo 反馈 github 文章目录 前言一、奇绘图册是什么&#xff1f;二、项目全景三、预览体验3.1 截图示例3.2 在线体验 四、功能介绍4.1 小程序4.2 服务端 五、安装部署5.1 快速开始~~5.2 手动部…...

大模型知识蒸馏技术(4)——离线蒸馏

版权声明 本文原创作者:谷哥的小弟作者博客地址:http://blog.csdn.net/lfdfhl离线蒸馏概述 离线蒸馏是知识蒸馏中最早被提出且最为常见的实现方式,其核心在于教师模型和学生模型的训练是分阶段进行的。具体而言,教师模型首先在训练集上进行充分训练,直至收敛,然后利用教…...

解决DeepSeek服务器繁忙的有效方法

全球42%的企业遭遇过AI工具服务器过载导致内容生产中断&#xff08;数据来源&#xff1a;Gartner 2025&#xff09;。当竞品在凌晨3点自动发布「智能家居安装指南」时&#xff0c;你的团队可能正因DeepSeek服务器繁忙错失「净水器保养教程」的流量黄金期⏳。147SEO智能调度系统…...

【C++游戏开发-五子棋】

使用C开发五子棋游戏的详细实现方案&#xff0c;涵盖核心逻辑、界面设计和AI对战功能&#xff1a; 1. 项目结构 FiveChess/ ├── include/ │ ├── Board.h // 棋盘类 │ ├── Player.h // 玩家类 │ ├── AI.h // AI类 │ └── Game.h // 游戏主逻辑 ├── src/ …...

Ubuntu 下 nginx-1.24.0 源码分析 - NGX_MAX_ALLOC_FROM_POOL

NGX_MAX_ALLOC_FROM_POOL 定义在 src\core\ngx_palloc.h #define NGX_MAX_ALLOC_FROM_POOL (ngx_pagesize - 1) 在 src/os/unix/ngx_alloc.h extern ngx_uint_t ngx_pagesize; 这个全局变量定义在 src\os\unix\ngx_alloc.c 中 ngx_uint_t ngx_pagesize; 在 src/os/unix/ngx_…...

等距节点插值公式

目录 等距节点插值公式Newton 前插公式Newton 后插公式 等距节点插值公式 将 Newton 差商插值多项式中各阶差商用相应差分代替&#xff0c;就可得到各种形式的等距节点插值公式&#xff0c;例如常用的前插公式与后插公式。 Newton 前插公式 如果节点 x k x 0 k h ( k 0 , …...