C# Dynamic & Expando

2023-03-09

筆記 C# Dynamic & Expando 的使用方式。

logo

說明

Dynamic 和 Expando Class 是 C# 語言提供的強大動態程式設計工具,它們可以使程式設計師以更直覺、更彈性的方式處理不確定型別和不確定的資料夾購。


C# 是一種靜態類型的語言,在編譯時就要確定變數的型別。

而 Dynamic 和 Expando 是 C# 4.0 引入的兩個特性,它們可以讓在靜態類型的語言中使用動態類型的行為。也就是在執行時 (Runtime) 才決定變數的型別和操作。

例如與動態類型的系統或函式庫互動,例如 COM、Python、Ruby 等,也可以更靈活地處理一些不確定或未知的資料結構。

Dynamic 是一個關鍵字,它可以用來宣告一個動態類型的變數,當使用 Dynamic 宣告一個變數時,編譯器不會對該變數做任何型別檢查或轉換,而是把所有的操作推遲到執行時去解析。例如:

dynamic x = 10; // x is an int at runtime
x = "Hello"; // x is a string at runtime
x = new System.Dynamic.ExpandoObject(); // x is an ExpandoObject at runtime

Expando 是一種特殊的 Class,它實現了 IDynamicMetaObjectProvider 介面,這表示它可以在執行時動態地新增、修改或移除屬性和方法。當使用 Expando 宣告一個物件時,可以像操作字典那樣操作該物件。例如:

dynamic obj = new System.Dynamic.ExpandoObject(); // obj is an empty ExpandoObject
obj.Name = "John"; // add a property Name with value "John"
obj.Age = 25; // add a property Age with value 25
obj.SayHello = (Action)(() => Console.WriteLine("Hello");

Expando 物件的另一個特點是,它可以實現事件的訂閱和取消訂閱。可以像操作委派那樣操作 Expando 物件的事件。例如

dynamic obj = new System.Dynamic.ExpandoObject(); // obj is an empty ExpandoObject
obj.OnChange = null; // add an event OnChange with null value
obj.OnChange += (EventHandler)((sender, args) => Console.WriteLine("Something changed.")); // subscribe to the event
obj.Name = "Mary"; // change the property Name
// output: Something changed.
obj.OnChange -= (EventHandler)((sender, args) => Console.WriteLine("Something changed.")); // unsubscribe from the event
obj.Age = 30; // change the property Age
// no output

Expando 物件是如何在執行時解析屬性、方法和事件的呢?Expando 物件內部維護了一個字典,用來存放所有的成員名稱和值。當存取或修改一個 Expando 物件的成員時,它就會在字典中查找或更新相應的項目。

當呼叫一個 Expando 物件的方法時,它就會把該方法轉換為委派並執行,而當觸發一個 Expando 物件的事件時,它就會把該事件轉換為 Delegate 執行。

應用

使用 Expando 動態載入 Excel COM 進行資料寫入

static void Main(string[] args)
{
	// Create an Expando object and initialize it as an Excel application instance
	dynamic excelApp = new System.Dynamic.ExpandoObject();
	excelApp = Activator.CreateInstance(Type.GetTypeFromProgID("Excel.Application"));

	excelApp.Visible = true;
	excelApp.Workbooks.Add();

	// Get the active worksheet
	dynamic worksheet = excelApp.ActiveSheet;

	// Write Data to worksheet
	Process[] processes = Process.GetProcesses();
	for (int i = 0; i < processes.Length; i++)
	{
		worksheet.Cells[i + 1, "A"] = processes[i].ProcessName;
		worksheet.Cells[i + 1, "B"] = processes[i].Threads.Count;
	}

	// save the workbook as a xlsx file
	string fileName = @"C:\Users\Public\test.xlsx";
	worksheet.SaveAs(fileName);

	// Quit Excel and release the COM objects
	excelApp.Quit();
}