[VS2010] C# 4.0 新功能:dynamic 型別

[VS2010] C# 4.0 新功能:dynamic 型別

image_8

C# 4.0 除了 Named Argument 和 Optional Parameter 以外,還多了一個特別的新玩意,叫做 dynamic 型別。dynamic 型別可以說是一種類似晚期繫結 (Late Binding) 的型態,它會告訴編譯器,在編譯期間 (compile-time) 不去檢查 dynamic 型別所代表的資料型態,而是在執行期間 (runtime) 才會決定,這代表了不用在程式中到處去宣告一個固定的型別,也不用再需要為了要編譯時期資料繫結而使用鬆散的 object 型別,由 C# 程式自動在執行期間獲取數值的型別即可。

 

例如下列的程式:

 

dynamic v = 124;

Console.Write(“value: {0}, type: {1}”, v, v.GetType());

 

其執行結果是:

 

image

 

不過以上的程式,在輸入變數 v 時,Visual Studio 不會出現 Intellisense 輔助,因為 Visual Studio 不會知道 v 的型別是什麼,因此也無法列舉出可用的成員。就算要使用 GetType() 取得型別,也要自己手動輸入(其他函式或成員亦是如此),同時 typeof 在 dynamic 型別上無法使用,若要使用 typeof 的話,會出現警告訊息,強行編譯也會出現編譯錯誤:

 

image

 

dynamic 型別可以在變數和參數上使用,例如下列的程式:

 

public class MyClass
{
    public int MethodA(int X, int Y)
    {
        return X * Y;
    }

    public dynamic MethodB(int X, int Y)
    {
        return X * Y;
    }

    public dynamic MethodC(dynamic X, dynamic Y)
    {
        return X * Y;
    }
}

 

MethodB 中的回傳值是 dynamic,這個最沒有爭議,它一定是 int 型別,但 MethodC 比較不同,參數也是 dynamic,這就會視傳入的參數型別來決定運算時的型別了,因此下列的程式:

 

dynamic myClass2 = new MyClass();

try
{
    Console.WriteLine("dynamic MyClass.MethodC result: {0}, type: {1}", myClass2.MethodC(15, 25), myClass2.MethodC(15, 25).GetType());
    Console.WriteLine("dynamic MyClass.MethodC result: {0}, type: {1}", myClass2.MethodC(15.2, 25), myClass2.MethodC(15.2, 25).GetType());
    Console.WriteLine("dynamic MyClass.MethodC result: {0}, type: {1}", myClass2.MethodC("15", 25), myClass2.MethodC("15", 25).GetType());
}
catch (Exception e)
{
    Console.WriteLine("Exception occurred: " + e.Message);
}

 

它的執行結果是:

 

image

 

可以注意到,前兩行的 dynamic 型別評估出來的資料型別是相容的,因此可以執行運算,但第三行是字串和整數相乘,字串和整數無法直接相容(隱含轉換),所以會擲出例外狀況。

另外,由於 dynamic 型別事先不知道成員,需要由開發人員手動輸入,所以如果輸入了根本不存在的成員時,也會擲出例外:

 

dynamic myClass2 = new MyClass();

try
{
    Console.WriteLine("dynamic MyClass call not exist method result: {0}", myClass2.MethodsNotExist());
}
catch (Exception e)
{
    Console.WriteLine("Exception occurred: " + e.Message);
}

 

image

 

變數間的型別轉換

 

dynamic 型別和實值的型別間,可以直接做隱含轉換 (implicit conversion),不論是左邊是 dynamic,或右邊是 dynamic 都一樣,例如:

 

// convert from given type to dynamic type.

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

 

// convert from dynamic to given type.

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

 

不過請注意,若要將 dynamic 和實值間轉換,如果 dynamic 的值和實值不相容的話,請務必做好明確轉換,否則會擲出 implicit casting 的例外。

 

dynamic v.s. var

 

看到 dynamic 的能力,用慣 LINQ 的開發人員一定會和另一個不明確指示變數型別的 var 型別聯想在一起,不過 var 雖然可以不指名型別,但是它卻是一個會在編譯時期檢查型別的資料型態,而 dynamic 是不會檢查資料型態的型別,所以如果在 var 中設定不存在的成員時,編譯器會擲回編譯錯誤,而且用 var 宣告的變數,其成員也會由 Intellisense 來列舉,可見 var 是可以在編譯時期決定型別的資料型態。

 

參考資料:

Using dynamic Type:

http://msdn.microsoft.com/en-us/library/dd264736(VS.100).aspx