淺談C#4 Dynamic


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();
        }
    }
}

要了解更加深入的方案,請看關於 ExpandoObjectDynamicObject 類的 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反射機制的性能優化。 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM