﻿# C# 4.0 新特性：動態型別、選用參數、具名參數

技術變化的可真快，C# 3.0 推出還不到兩年，估計不久 C# 4.0 可能就要出爐了，這幾天抽空看了一下關於 C# 4.0 的新特性，感覺未來寫 C# 會越來越有 "彈性"，是好是壞見仁見智，但我還蠻期待的，今天我就簡單介紹幾個 C# 4.0 的新特性。

### Dynamic Lookup ( 動態對應 )

C# 4.0 最大的強化即所謂的「**動態編程**」( dynamic programming )，他可以讓把既有的 "靜態物件" 標記為 "動態物件"。

C# 編譯器原本需要在編譯時期(Compile-time)就檢查程式碼中物件的型別(Type)是否一致，即便 C# 3.0 帶來一個所謂 [var](http://msdn.microsoft.com/zh-tw/library/bb383973.aspx) 變動型別，不過骨子裡還是一樣是屬於 "靜態型別"，只是在編譯時 C# 編譯器會將 [var](http://msdn.microsoft.com/zh-tw/library/bb383973.aspx) 編譯成明確的型別(Type)，因此在編譯時期一樣會檢查型別是否有問題。

不過 C# 4.0 新增的 dynamic 動態型別有點不太一樣，雖然骨子裡一樣是屬於 "靜態型別"，不過被宣告為 dynamic 的型別，編譯器(Compiler)不會進行型別檢查，而是讓程式在執行時讓 .NET Framework Runtime 進行型別檢查，等於是「延後檢查」罷了，並**不是**「不檢查型別」喔！

在 [New Features in C# 4.0](https://web.archive.org/web/20101225102339/http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=csharpfuture&DownloadId=3550) 文件中提到了四個可善用動態特性的例子：

-   從動態語言來的動態物件存取，例如：Python 或 Ruby 等
-   透過 IDispatch 存取 COM 物件
-   原本透過 Reflection (反映) 存取 .NET 型別的方式將可透過 dynamic 型別簡化操作
-   處理會不斷改變結構的物件，例如：HTML DOM 物件

可標記 dynamic 型別的範圍很多，包括方法(method), 運算子(operator), 索引子呼叫(indexer call), 屬性(property), 欄位(field), 甚至於可動態物件叫用(object invocations)，這樣講看不出威力，看幾個程式碼範例吧：

```
dynamic d = GetDynamicObject(…);
d.M(7);              // 呼叫「動態方法」 
d.f = d.P;           // 動態 取得/設定 屬性/欄位
d["one"] = d["two"]; // 動態透過索引子取得/設定資料
int i = d + 3;       // 動態呼叫運算子(operators)
string s = d(5,7);   // 把 d 當成委派(delegate)來使用
```

以上例子的 d 被宣告成 dynamic 型別，意思是說任何對 d 所做的操作都是 "**動態的**"，所以當編譯器讀到 d.M 方法時不會進行任何型別檢查，且不管你呼叫什麼方法(method)、傳入幾個參數、或任意型別的參數都沒關係，所有的型別驗證都會留到 runtime 時才會進行。而其他的例子應該也淺顯易懂，總之全部都變動態了。

C# 編譯器在編譯這些程式時只會將該程式碼轉成一些 metadata 告訴 Runtime 這段程式「預期應該怎樣執行，請照我的規格來進行呼叫」，至於型別都是執行時期才決定的。

在更進一步的範例如下：

```
Foo foo = new Foo();
dynamic d = new Bar();
var result = foo.M(d);
```

即便 Foo 編譯時是「靜態型別」，只要傳入的參數有一個以上的 dynamic 型別參數，連 M 都可以是**動態的**，有沒有覺得這樣的設計實在是**太有彈性了**。

### Named and Optional Arguments ( 具名與選用參數 )

C# 也越來越像 VB.NET 了，具名與選用參數這兩個功能在 VB.NET 裡老早就有了，直到 C# 4.0 終於要加入了，我覺得這個特性蠻不錯的，以後在設計方法時就不用寫那麼多 overload 方法，且呼叫方法時也變的非常的方便，參數可以設定預設值，且不用每個參數都傳入了。如果你用 C# 寫過 Office Automation 的程式就知道為什麼選用參數有多棒了！

*註：選用參數也是 JavaScript 的特性之一，所以 C# 與 JavaScript 也越來越像了。*

看範例比較快：

```
// 宣告一個 M 方法，其中第二、第三個參數是包含預設值的選用參數
public void M(int x, int y = 5, int z = 7);
// 宣告方法與呼叫方法與 JavaScript 簡直如出一轍
M(1, 2, 3); // 標準呼叫法
M(1, 2);    // 忽略 z 參數，等同於呼叫 M(1, 2, 7) 因為 z 的預設值為 7
M(1);       // 忽略 y 與 z 參數，等同於呼叫 M(1, 5, 7)
```

不用我多說了把，想想 JavaScript 是是怎麼寫的吧，不過 C# 4.0 是不允許你這樣寫的：

```
M(1, , 3); // C# 4.0 不允許忽略參數傳入
```

由於 C# 4.0 不允許忽略參數傳入，所以要忽略參數的話，就必須要靠「**具名參數**」的寫法，這點跟 VB.NET 是一樣的：

```
M(1, z: 3);    // 想忽略第2的參數，那第三個參數就用具名參數的寫法
M(x: 1, z: 3); // 也可全部都用具名參數的寫法
M(z: 3, x: 1); // 傳入具名參數是不需考慮順序的
```

剩下還有一些 C# 4.0 的新特性像是 Features for COM interop、Variance、Relationship with Visual Basic 等各位有空可以自行查閱 [New Features in C# 4.0](https://web.archive.org/web/20101225102339/http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=csharpfuture&DownloadId=3550) 文件，另外像是程式碼範例也可以在 [C# Future](https://web.archive.org/web/20081101224739/http://code.msdn.microsoft.com:80/csharpfuture) 網站下載的到。

我現在有點難以想像未來的程式都**動態化**之後，很有可能會造成除錯上的困擾，尤其是當程式上線之後，程式在客戶端會怎麼執行、客戶會怎麼使用都不知道，若真的遇到一些難以解決的錯誤時，恐怕也很難透過 Exception 訊息得知真正的錯誤來源與發生錯誤的地方，例如說若錯誤來自於其他的動態語言，不知道 Stack Trace 會不會一樣的完整？

**相關連結**

-   [C# Future - MSDN Code Gallery](https://web.archive.org/web/20081101224739/http://code.msdn.microsoft.com:80/csharpfuture)
-   [New Features in C# 4.0](https://web.archive.org/web/20101225102339/http://code.msdn.microsoft.com/Project/Download/FileDownload.aspx?ProjectName=csharpfuture&DownloadId=3550)
-   [Visual C# Developer Center](http://www.csharp.net/)
-   [C# 4.0 新功能：動態繫結](http://huan-lin.blogspot.com/2009/02/dynamic-binding-in-csharp-4.html)
-   [C# 4.0（VB 10）與CLR 4.0之驚鴻一瞥](https://web.archive.org/web/20171120002808/http://blog.sina.com.tw/dotnet/article.php?pbgid=4907&entryid=580479)
-   [Inside C# 4.0: dynamic typing, optional parameters, covariance and contravariance](http://channel9.msdn.com/shows/Going+Deep/Inside-C-40-dynamic-type-optional-parameters-more-COM-friendly/)
-   [C# 4.0 Optional Parameters](http://geekswithblogs.net/michelotti/archive/2009/02/05/c-4.0-optional-parameters.aspx)
-   [C# 4.0 Named Parameters for better code quality](http://geekswithblogs.net/michelotti/archive/2009/01/22/c-4.0-named-parameters-for-better-code-quality.aspx)
