C#4.0新增功能01 動態綁定 (dynamic 類型)

  C# 4 引入了一個新類型 dynamic。 該類型是一種靜態類型,但類型爲 dynamic 的對象會跳過靜態類型檢查。 大多數狀況下,該對象就像具備類型 object 同樣。 在編譯時,將假定類型化爲 dynamic 的元素支持任何操做。 所以,沒必要考慮對象是從 COM API、從動態語言(例如 IronPython)、從 HTML 文檔對象模型 (DOM)、從反射仍是從程序中的其餘位置獲取本身的值。 可是,若是代碼無效,則在運行時會捕獲到錯誤。  html

  在經過 dynamic 類型實現的操做中,該類型的做用是繞過編譯時類型檢查。 改成在運行時解析這些操做。 dynamic 類型簡化了對 COM API(例如 Office Automation API)、動態 API(例如 IronPython 庫)和 HTML 文檔對象模型 (DOM) 的訪問。編程

  在大多數狀況下,dynamic 類型與 object 類型的行爲相似。 可是,若是操做包含 dynamic類型的表達式,那麼不會經過編譯器對該操做進行解析或類型檢查。 編譯器將有關該操做信息打包在一塊兒,以後這些信息會用於在運行時評估操做。 在此過程當中,dynamic 類型的變量會編譯爲 object 類型的變量。 所以,dynamic 類型只在編譯時存在,在運行時則不存在。app

下面的示例將 dynamic 類型的變量與 object 類型的變量進行對比。 若要在編譯時驗證每一個變量的類型,請將鼠標指針放在 WriteLine 語句中的 dyn 或 obj 上。 IntelliSense 對 dyn 顯示「dynamic」 ,對 obj 顯示「object」 。dom

class Program
{
    static void Main(string[] args)
    {
        dynamic dyn = 1;
        object obj = 1;

        System.Console.WriteLine(dyn.GetType());
        System.Console.WriteLine(obj.GetType());
    }
}

輸出結果:編程語言

若要查看編譯時 dyn 與 obj 之間的區別,請在前面示例的聲明和 WriteLine 語句之間添加下列兩行:ide

dyn = dyn + 3;
obj = obj + 3;

嘗試在表達式 obj + 3 中添加整數和對象時,將報告編譯器錯誤。 可是,對於 dyn + 3,不會報告任何錯誤。 在編譯時不會檢查包含 dyn 的表達式,緣由是 dyn 的類型爲 dynamic函數

上下文

dynamic 關鍵字能夠直接出現,也能夠做爲構造類型的組件在下列狀況中出現:ui

  • 在聲明中,做爲屬性、字段、索引器、參數、返回值、本地變量或類型約束的類型。下面的類定義在多個不一樣的聲明中使用 dynamicspa

class ExampleClass
{
    // 動態字段
    static dynamic field;

    // 動態屬性
    dynamic prop { get; set; }

    // 動態返回類型和動態類型參數
    public dynamic exampleMethod(dynamic d)
    {
        // 局部動態變量
        dynamic local = "Local variable";
        int two = 2;

        if (d is int)
        {
            return local;
        }
        else
        {
            return two;
        }
    }
}
  • 在顯式類型轉換中,做爲轉換的目標類型。指針

static void convertToDynamic()
{
    dynamic d;
    int i = 20;
    d = (dynamic)i;
    Console.WriteLine(d);

    string s = "Example string.";
    d = (dynamic)s;
    Console.WriteLine(d);

    DateTime dt = DateTime.Today;
    d = (dynamic)dt;
    Console.WriteLine(d);

}
// 輸出結果:
// 20
// Example string.
// 7/25/2018 12:00:00 AM
  • 在如下任何狀況下:類型用做值(如 is 運算符或 as 運算符右側),或者用做構造類型中 typeof 的參數。 例如,能夠在下列表達式中使用 dynamic
int i = 8;
dynamic d;
// 使用 is 操做符
// 在此處動態類型和object類似,The dynamic type behaves like object。除非 somevar 的值爲 null ,不然如下表達式將返回true
if (someVar is dynamic) { }

// 使用 as 操做符
d = i as dynamic;

// 使用typeof, 做爲構造類型的一部分
Console.WriteLine(typeof(List<dynamic>));

// 如下語句致使編譯器錯誤
//Console.WriteLine(typeof(dynamic));
示例
下面的示例在多個聲明中使用 dynamic。 Main 方法也將編譯時類型檢查與運行時類型檢查進行了對比。
using System;

namespace DynamicExamples
{
    class Program
    {
        static void Main(string[] args)
        {
            ExampleClass ec = new ExampleClass();
            Console.WriteLine(ec.exampleMethod(10));
            Console.WriteLine(ec.exampleMethod("value"));

            // 下面的語句會引起編譯器異常。由於 exampleMethod 方法僅包含一個參數
            //Console.WriteLine(ec.exampleMethod(10, 4));

            dynamic dynamic_ec = new ExampleClass();
            Console.WriteLine(dynamic_ec.exampleMethod(10));

            // 由於 dynamic_ec 是 dynamic 類型, 下面的調用(傳遞了2個參數)不會引起編譯器異常。
            // 可是在運行時會引起異常。
            //Console.WriteLine(dynamic_ec.exampleMethod(10, 4));
        }
    }

    class ExampleClass
    {
        static dynamic field;
        dynamic prop { get; set; }

        public dynamic exampleMethod(dynamic d)
        {
            dynamic local = "Local variable";
            int two = 2;

            if (d is int)
            {
                return local;
            }
            else
            {
                return two;
            }
        }
    }
}
// 輸出結果:
// Local variable
// 2
// Local variable
使用 dynamic

  以上示例中,編譯器的做用是將有關每一個語句的預期做用的信息一塊兒打包到類型化爲 dynamic 的對象或表達式。 在運行時,將對存儲的信息進行檢查,而且任何無效的語句都將致使運行時異常。

大多數動態操做的結果是其自己 dynamic。 例如,若是將鼠標指針放在如下示例中使用的 testSum 上,則 IntelliSense 將顯示類型「(局部變量)dynamic testSum」 。

dynamic d = 1;
var testSum = d + 3;

System.Console.WriteLine(testSum);

結果不爲 dynamic 的操做包括:

  • 從 dynamic 到另外一種類型的轉換。
  • 包括類型爲 dynamic 的自變量的構造函數調用。

例如,如下聲明中 testInstance 的類型爲 ExampleClass,而不是 dynamic

var testInstance = new ExampleClass(d);
轉換

動態對象和其餘類型之間的轉換很是簡單。 這樣,開發人員將可以在動態行爲和非動態行爲之間切換。

任何對象均可隱式轉換爲動態類型,如如下示例所示。

dynamic d1 = 7;
dynamic d2 = "a string";
dynamic d3 = System.DateTime.Today;
dynamic d4 = System.Diagnostics.Process.GetProcesses();

反之,隱式轉換也可動態地應用於類型爲 dynamic 的任何表達式。

 

int i = d1;
string str = d2;
DateTime dt = d3;
System.Diagnostics.Process[] procs = d4;

 

使用類型爲 dynamic 的參數重載決策
  若是方法調用中的一個或多個參數的類型爲 dynamic,或者方法調用的接收方的類型爲 dynamic,則會在運行時(而不是在編譯時)進行重載決策。 在如下示例中,若是惟一可訪問的 exampleMethod2 方法定義爲接受字符串參數,則將 d1 做爲參數發送不會致使編譯器錯誤,但卻會致使運行時異常。 重載決策之因此會在運行時失敗,是由於 d1 的運行時類型爲 int,而 exampleMethod2 要求爲字符串。
ec.exampleMethod2("a string");

ec.exampleMethod2(d1);
動態語言運行時
  動態語言運行時 (DLR) 是 .NET Framework 4 中的一個新 API。 它提供了支持 C# 中 dynamic 類型的基礎結構,還提供了 IronPython 和 IronRuby 等動態編程語言的實現。 有關 DLR 的詳細信息,請參閱動態語言運行時概述
COM 互操做

C# 4 包括若干功能,這些功能改善了與 COM API(例如 Office 自動化 API)的互操做體驗。 這些改進之處包括 dynamic 類型以及命名參數和可選參數的用法。

經過將類型指定爲 object,許多 COM 方法都容許參數類型和返回類型發生變化。 這樣,就必須顯式強制轉換值,以便與 C# 中的強類型變量保持協調。 若是使用 /link(C# 編譯器選項)選項進行編譯,則能夠經過引入 dynamic 類型將 COM 簽名中出現的 object 看做是 dynamic 類型,從而避免大量的強制轉換。 例如,如下語句對比了在使用 dynamic 類型和不使用 dynamic 類型的狀況下如何訪問 Microsoft Office Excel 電子表格中的單元格。

// 引入動態以前
((Excel.Range)excelApp.Cells[1, 1]).Value2 = "Name";
Excel.Range range2008 = (Excel.Range)excelApp.Cells[1, 1];
// 在引入 dynamic 以後,對 value 屬性的訪問以及到 excel.range 的轉換將由運行時 COM 綁定器處理
excelApp.Cells[1, 1].Value = "Name";
Excel.Range range2010 = excelApp.Cells[1, 1];
Title 說明
dynamic 描述 dynamic 關鍵字的用法。
動態語言運行時概述 提供有關 DLR 的概述,DLR 是一種運行時環境,它將一組適用於動態語言的服務添加到公共語言運行時 (CLR)。
演練:建立和使用動態對象 提供有關如何建立自定義動態對象以及建立訪問 IronPython 庫的對象的分步說明。
如何:經過使用 Visual C# 功能訪問 Office 互操做對象 演示如何建立一個項目,該項目使用命名參數和可選參數、dynamic 類型以及可簡化對 Office API 對象的訪問的其餘加強功能。
 
相關文章
相關標籤/搜索