C#的dynamic类型是什么?它与object有什么不同?

dynamic类型在C#中延迟类型检查至运行时,由DLR解析动态调用,允许直接访问成员而无需显式转换,与object需强制转型不同,适用于COM交互、JSON解析等场景,但会丧失编译时检查、影响性能且增加运行时异常风险。

dynamic 是 C# 中一种特殊的类型,它告诉编译器在编译时不进行类型检查,而是将类型解析推迟到运行时。这使得你可以像在动态语言(如 Python 或 JavaScript)中一样调用方法、访问属性或执行操作,而不需要事先知道对象的确切类型。

dynamic 的基本行为

当你把一个对象声明为 dynamic,编译器会跳过对该变量的所有静态类型检查。所有对它的操作都会被封装成“动态调用”,并在程序运行时由 DLR(Dynamic Language Runtime)来解析。

例如:
dynamic obj = "Hello";
Console.WriteLine(obj.Length); // 运行时确定 Length 是否存在

obj = 123; Console.WriteLine(obj + 456); // 正确:运行时按 int 处理

如果调用了一个不存在的成员,会在运行时报错(RuntimeBinderException),而不是编译时报错。

与 object 的主要区别

虽然 object 可以存储任何类型的值,但它和 dynamic 在使用上有本质不同:

  • object 是所有类型的基类,但所有操作都必须通过显式类型转换才能访问具体成员。编译器对 object 类型做严格的静态检查。
  • dynamic 绕过编译时检查,直接在运行时解析操作,写法更简洁,适合处理 COM 对象、反射、JSON 解析等场景。

对比示例:

// 使用 object:需要强制转换
object objObj = "Hello";
int len1 = ((string)objObj).Length;

// 使用 dynamic:直接调用,无需转换 dynamic objDyn = "Hello"; int len2 = objDyn.Length;

上面两种方式最终结果相同,但 dynamic 写起来更自然,也更容易出错(因为错误只能在运行时发现)。

适用场景与注意事项

dynamic 适合以下情况:

  • 与动态语言互操作(如 IronPython)
  • 处理 Office COM 接口
  • 解析结构不确定的 JSON 数据(配合 ExpandoObject)
  • 简化反射代码

但要注意:

  • 失去编译时错误检查,容易引发运行时异常
  • 性能略低,因为每次调用都要经过 DLR 解析
  • IDE 无法提供智能提示或重构支持

基本上就这些。dynamic 提供了灵活性,但也增加了风险,应谨慎使用。