聊到 C# 的 dynamic,很多人第一反应是“运行时类型”,但这种理解其实不太对。它并不是运行时态,而更像是一张编译器给开的“后门通行证”。简单说,你把变量声明为 dynamic,编译器就不再检查你有没有写对成员名、参数个数对不对、能不能赋值——这些事全推到运行时,交给 DLR(动态语言运行时)去处理。要是用错了地方,直接甩你一个 RuntimeBinderException,连个调试的余地都不给。

什么场景非用 dynamic 不可?

关键不在于“能不能装任意值”,而在于“调用成员的时候要不要走 DLR 绑定”。你可以试试看,object 上调用方法直接编译不过去(除非你用反射),而 dynamic 会把整个调用链——方法名、参数、重载选择——打包成一个 CallSite,等到运行时才去查目标对象到底有没有那个方法。哪些场景非它不可?

dynamic 赋值后类型变了吗?

这个要分清楚:变量本身类型始终是 dynamic,但所指向的底层值可以是任意类型。IntelliSense 显示的是声明类型,不是值类型。看个例子就明白了:

dynamic d = 42;
Console.WriteLine(d.GetType()); // System.Int32
d = "hello";
Console.WriteLine(d.GetType()); // System.String
d = new[] { 1, 2, 3 };
Console.WriteLine(d.GetType()); // System.Int32[]

这里 var 真代替不了。var d = 42; 推导出来是 int,后面不能再赋值字符串。但 dynamic 可以跨类型赋值,而且每次 .GetType() 返回的都是真实运行时类型。

为什么 dynamic_ec.exampleMethod1(10, 4) 是运行时抛异常而不是编译报错?

编译器对 dynamic 表达式的任何成员访问——方法、属性、索引器——都生成 CallSite,把调用信息缓存起来,等到第一次执行才尝试绑定。DLR 的查找顺序是这样的:

所以即使 ExampleClass 只定义了 exampleMethod1(int i)dynamic_ec.exampleMethod1(10, 4) 还是会走到第 4 步失败,错误信息类似 'ExampleClass' does not contain a definition for 'exampleMethod1'

那些容易被忽略的性能与调试陷阱

dynamic 绑定的开销比想象中大。首次调用慢——要构建和缓存 CallSite;后续同签名调用快——命中缓存;但一旦参数类型组合发生变化(比如从 int 换成 long),又触发新绑定。更麻烦的是调试体验:

真正难缠的不是语法本身,而是你得想清楚:这个 dynamic 值从哪来、生命周期内可能是什么类型、谁负责保证它有你要调的方法。这些责任全移交给了程序员,编译器不再兜底。

本文转载于:https://www.php.cn/faq/2344499.html 如有侵犯,请联系zhengruancom@outlook.com删除。
免责声明:正软商城发布此文仅为传递信息,不代表正软商城认同其观点或证实其描述。