dynamic 是 C# 4.0 引入的**靜態類型**,但編譯器對其操作**延遲到執行時期**進行綁定。聲明為 dynamic 的變數,編譯時不檢查成員是否存在,執行時透過 DLR (Dynamic Language Runtime) 動態調度。
dynamic d = Console.Out; // 可接受任何物件
d.WriteLine("Hello DLR!"); // 執行時解析 WriteLine 方法
d.NonExistMethod(); // 編譯通過,執行時拋 RuntimeBinderException
dynamic x = 10;
x++; x--; // 支援運算子
int i = x; // 隱式轉換回靜態類型
| 特性 | var | dynamic |
|---|---|---|
| 類型推斷時機 | 編譯期(初始化時即確定) | 執行期(每次操作動態綁定) |
| 適用範圍 | 僅區域變數 | 欄位、屬性、參數、返回值、泛型參數 |
| 重新賦值不同類型 | 不允許 | 允許 |
| IntelliSense 支援 | 完整 | 無(編譯期類型未知) |
| 性能 | 零開銷 | 有 DLR 快取開銷 |
// 反射調用 instance.GetName()
var asm = Assembly.GetExecutingAssembly();
var obj = asm.CreateInstance("MyNamespace.MyClass");
var mi = obj.GetType().GetMethod("GetName");
string name = (string)mi.Invoke(obj, null);
// dynamic 調用
dynamic dyn = new MyClass();
string name = dyn.GetName(); // 一行搞定
限制:dynamic **不支援屬性存取**(`dyn.Prop` 會失敗),因屬性編譯為 `get_Prop`/`set_Prop` 方法,DLR 目前不自動映射。需手動呼叫 `dyn.get_Prop()`(但實測仍失敗,建議改用反射或介面)。
簡單代碼:
dynamic d = "str";
d.ToString();
編譯器生成(Reflector 反編譯 .NET 4.0 模式):
object d = "str";
if (<>o__SiteContainer0.<>p__Site1 == null)
<>o__SiteContainer0.<>p__Site1 = CallSite<Action<CallSite, object>>.Create(
new CSharpInvokeMemberBinder(
CSharpCallFlags.None, "ToString", typeof(Program), null,
new[] { new CSharpArgumentInfo(CSharpArgumentInfoFlags.None, null) }));
<>o__SiteContainer0.<>p__Site1.Target(<>o__SiteContainer0.<>p__Site1, d);
dynamic 會發生裝箱(`object d = 5`)。dynamic 讓 C# 具備動態語言特性,極大簡化 COM 互操作、動態語言互通、晚期綁定場景代碼。但需理解其**執行時綁定、CallSite 快取、裝箱開銷**本質,在效能敏感場合謹慎使用。