Dynamic關鍵字和DLR是C#4和.NET Framework 4中重大的新增功能!
1.什么是“動態”?
一般而言,動態語言不執行編譯時類型檢查,僅在運行時識別對象的類型。缺少編譯時類型檢查也會導致 IntelliSense 功能無效。
C# 最初是作為純靜態語言創建的,但 C# 4 添加了一些動態元素,用以改進與動態語言和框架之間的互操作性。C# 團隊考慮了多種設計選項,但最終確定添加一個新關鍵字來支持這些功能:dynamic。
當我們使用 dynamic 關鍵字時,我們就告訴了編譯器關閉編譯時檢查。網上以及 MSDN 文檔中有大量關於如何使用該關鍵字的示例。
2.Dynamic、Object 、Var區別
關鍵字 object 表示 System.Object 類型,它是 C# 類層次結構中的根類型。此關鍵字經常在編譯時無法確定對象類型時使用,而這種情況經常在各種互操作性情形中發生。
從 C# 3.0 起,關鍵字 var 開始用於隱式類型化局部變量以及匿名類型。此關鍵字經常與 LINQ 結合使用。當使用 var 關鍵字聲明變量時,將在編譯時根據初始化字符串推斷該變量的類型。在運行時無法更改該變量的類型。如果編譯器不能推斷類型,它會生成一個編譯錯誤。
C# 4 中引入的 dynamic 關鍵字可使某些傳統上依賴於 object 關鍵字的情形更容易編寫和維護。實際上,動態類型在后台使用 System.Object 類型。但與 object 不同的是,動態類型不需要在編譯時執行顯式轉換操作,因為它僅在運行時識別類型。
3.Dynamic一般用法示例
基本的用法,用代碼來說吧:
using System; using System.Reflection; namespace csdlr { public class Employee { public string FirstName { get; set; } public void Speak() { Console.WriteLine("My name is {0}", FirstName); } } class Program { static void Main(string[] args) { ////Error 1: //var o_1 = GetASpeaker(); //o_1.Speak(); ////Error 2: //object o_2 = GetASpeaker(); //o_2.Speak(); //1.普通 Employee o = GetASpeaker() as Employee;//var o=GetASpeaker();//OK also. o.Speak(); //2.反射 object o1 = GetASpeaker(); o1.GetType().GetMethod("Speak").Invoke(o, null); //3.Dynamic dynamic o2 = GetASpeaker(); o2.Speak(); Console.ReadKey(); //程序並未添加Dogs這個程序集的引用,其和可執行程序在同一目錄下即可 //反射程序集,動態創建其類型實例,並調用其方法 Type dogType = Assembly.Load("Dogs").GetType("Dogs.Dog");//注意:完全限定名,困惑了好久! dynamic dog = Activator.CreateInstance(dogType); dog.Speak(); Console.ReadKey(); } private static object GetASpeaker() { return new Employee() { FirstName = "DebugLZQ" }; } } }
Dogs類庫如下:
View Code
using System; namespace Dogs { public class Dog { public void Speak() { Console.WriteLine("Woof"); } } }
其編譯后為Dogs.dll。
4.Dynamic關鍵字
using System; using System.Dynamic; namespace ExpandoSample { class Program { static void Main(string[] args) { //ExpandoObject:表示一個對象,該對象包含可在運行時動態添加和移除的成員。 dynamic expando=new ExpandoObject(); expando.Name = "DebugLZQ"; expando.Speak = new Action(()=>Console.WriteLine("My name is {0}",expando.Name )); expando.Speak(); Console.ReadKey(); } } }
要了解更加深入的方案,請看關於 ExpandoObject 和 DynamicObject 類的 MSDN 文檔。同時,還有一些值得一看的文章,比如由 Bill Wagner 撰寫的文章“動態方法包 。
5.動態功能與 COM 互操作
C# 團隊在 C# 4 版本中專門考慮的 COM 互操作方案是針對 Microsoft Office 應用程序(如 Word 和 Excel)進行編程。他們的目的是讓這一任務在 C# 中變得像在 Visual Basic 中那樣容易和自然。
using System; using System.Diagnostics; namespace dynamicExcel { class Program { static void Main(string[] args) { Type excelType = Type.GetTypeFromProgID("Excel.Application"); dynamic excel = Activator.CreateInstance(excelType); excel.Visible = true; excel.Workbooks.Add(); dynamic sheet = excel.ActiveSheet; Process[] processes = Process.GetProcesses(); for (int i = 0; i < processes.Length ; i++) { sheet.Cells[i + 1, "A"] = processes[i].ProcessName; sheet.Cells[i + 1, "B"] = processes[i].Threads.Count; } } } }
6.類包裝
使用它可以為自己的庫提供更好的語法,或為現有庫創建包裝。
using System; using System.Xml.Linq; namespace EncodXML { class Program { static void Main(string[] args) { //處理XML基本就這三種框架 //1.XmlDocument //... //2.LINQ to XML //... //3.XDocument var doc = XDocument.Load("Employees.xml"); foreach (var employee in doc.Element("Employees").Elements("Employee")) { Console.WriteLine(employee.Element("FirstName").Value ); } //Dynamic包裝-提供更簡潔的語法 var doc2 = XDocument.Load("Employees.xml").AsExpando(); foreach (var employee in doc2.Employees) { Console.WriteLine(employee.FirstName); } } } }
using System.Collections.Generic; using System.Linq; using System.Xml.Linq; using System.Dynamic; namespace EncodXML { public static class ExpandoXML { public static dynamic AsExpando(this XDocument xDocument) { return CreateExpando(xDocument.Root); } private static dynamic CreateExpando(XElement element) { var result = new ExpandoObject() as IDictionary<string, object>; if(element.Elements().Any(e=>e.HasElements )) { var list = new List<ExpandoObject>(); result.Add(element.Name.ToString(),list); foreach(var childElement in element.Elements()) { list.Add(CreateExpando(childElement )); } } else { foreach (var leafElement in element.Elements()) { result.Add(leafElement.Name.ToString(),leafElement.Value ); } } return result; } } }
View Code
<?xml version="1.0" encoding="utf-8" ?> <Employees> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> <Employee> <FirstName>DebugLZQ</FirstName> </Employee> </Employees>
其他
關於反射與Dynamic使用方法對照
using System; using System.Reflection; namespace LoadAssembly { class Program { static void Main(string[] args) { Type dogType = Assembly.Load("Dogs").GetType("Dogs.Dog"); dynamic dog = Activator.CreateInstance(dogType); dog.Speak(); Console.ReadKey(); object dog2 = Activator.CreateInstance(dogType); dog2.GetType().GetMethod("Speak").Invoke(dog2, null); Console.ReadKey(); } } }

關於Dynamic優化反射性能請看:淺談.NET反射機制的性能優化。

