.NET 4 引入 dynamic 與 ExpandoObject,讓 C# 具備動態語言特性。但開源專案 Clay (CodePlex) 更進一步,提供極具表達力的流暢介面,讓物件初始化、陣列建構、動態介面實作如同 JavaScript 般直觀。本文將帶你體驗這些「不可思議」的寫法。
// NuGet: Install-Package Clay
dynamic New = new ClayFactory();
以下寫法完全等價,皆產生擁有 FirstName、LastName 屬性的動態物件:
// 1. 屬性指派
var p1 = New.Person();
p1.FirstName = "Louis";
p1.LastName = "Dejardin";
// 2. 索引器指派
var p2 = New.Person();
p2["FirstName"] = "Louis";
p2["LastName"] = "Dejardin";
// 3. jQuery 風格鏈式呼叫
var p3 = New.Person().FirstName("Louis").LastName("Dejardin");
// 4. 匿名型別
var p4 = New.Person(new { FirstName = "Louis", LastName = "Dejardin" });
// 5. 命名參數
var p5 = New.Person(FirstName: "Louis", LastName: "Dejardin");
核心機制:Person、FirstName、LastName 皆為動態成員,Clay 透過 DynamicObject 攔截呼叫並建構屬性包。
// 建構陣列
var people = New.Array(
New.Person().FirstName("Louis").LastName("Dejardin"),
New.Person().FirstName("Bertrand").LastName("Le Roy")
);
// 存取
int count = people.Count; // 2
string name = people[0].FirstName; // "Louis"
// 動態新增陣列屬性
people[0].Aliases("Lou", "Loulou"); // 參數陣列
people[0].Aliases(new[] { "Lou" }); // 陣列
people[0].Aliases.Add("loudej"); // List 風格
public interface IPerson
{
string FirstName { get; set; }
string LastName { get; set; }
}
// Clay 物件自動滿足介面契約
dynamic New = new ClayFactory();
var people = New.Array(
New.Person().FirstName("Louis").LastName("Dejardin"),
New.Person().FirstName("Bertrand").LastName("Le Roy")
);
IPerson lou = people[0]; // 隱含轉型成功!
string fullName = lou.FirstName + " " + lou.LastName; // "Louis Dejardin"
Clay 內部產生實作 IPerson 的動態 Proxy,無需類別宣告即可滿足靜態型別檢查。
專案網址:https://clay.codeplex.com(現已歸檔,可參考 GitHub Fork 版本)。