好的設計是取得適當的折衷 - C# 語言特色淺探

好的程式語言必須讓程序員專注在功能上的開發,而不是被程式語言給制約。這是我個人的感觸,使用 MFC 開發 UI 實在是太過痛苦了,常常得查線上文件 API 的使用方式,光是字體跟字串就可以搞得很複雜。我實在很不喜歡心至碼不至的感覺,所以下定決定轉換到 C#,來看看 C# 有什麼特別吸引我的功能:

LINQ(Language-Integrated Query) (C# 3.0)

一般我們只能對資料庫下 SQL 的語法,但是 C# 中我們可以透過 SQL-like 的方式直接對 List, Array 等常用的 LINQ-enabled 資料結構直接做查詢取值的動作!功能很強大,使用起來卻毫無負擔!

1 2 3 4 5 6
int[] scores =[new](http://www.google.com/search?q=new+msdn.microsoft.com)int[]{97, 92, 81, 60}; IEnumerable<int> scoreQuery =from score in scores                               where score >80                               select score; foreach(int i in scoreQuery)     Console.Write(i +" ");
## dynamic 型別 (C# 4.0)

如果將變數宣告為 dynamic,就會如動態語言一樣,該變數的型別會在執行階段動態的變化。

1 2 3
dynamic calc = GetCalculator(); int sum = calc.Add(10, 20); var calc = GetCalculator();// Anonymous Type (C# 3.0)
匿名類別的功能類似,不在程式中宣告,交由 Compiler 自行推斷。

Boxing and Unboxing

Boxing 的動作就是把資料型態的變數封裝為物件,這兩者最主要的差異在於 Value type 與 Reference type。網路上可以找到許多分析這兩者差異的文章,大多數都著重在它們被分配到記憶體中的位置是 Heap or Stack。但這其實都取決於實作,重要的是這兩者的 copy-semantics。
– Value type: 賦值時是複製對象,通常存在於 Stack,沒有 GC 介入管理下,有效能上的優勢。
– Reference type: 賦值時是參考對象,通常存放於 Heap,GC 會介入,可能因此影響效能。

1 2 3
int i =123; object o =(object)i;  // boxing int j =(int)o;        // unboxing
Java 也同樣有提供 boxing/unboxing 的功能,可以讓我們自行決定變數是否要被 GC 介入。

Managed/Unmanaged Code Interoperability

如果上面的功能不夠過癮,控制欲極強的你,C# 也提供使用 Unmanaged Code 的方式:

1 2 3 4 5 6 7 8 9 10
publicstaticunsafevoid Main() {     int* fib =stackallocint[100];     int* p = fib;     *p++=*p++=1;     for(int i=2; i&lt;100;++i, ++p)        *p = p[-1]+ p[-2];     for(int i=0; i&lt;10;++i)        Console.WriteLine(fib[i]); }
你可能會好奇,那麼[可以自行決定要將記憶體分配到 Heap/Stack 嗎?](http://stackoverflow.com/questions/2031258/c-sharp-structs-classes-stack-heap-control)答案如前述所說,這決定於 C# runtime 最佳化實作方式。

Lambda Expression (C# 3.0)

Lambda 在函數語言與動態語言你可能已經很熟悉,C# 也順應潮流提供了此功能:

1
listOfFoo.Where(x => x.Size>10);
## Extension Method (C# 3.0)

透過擴展方法,我們可以外掛一個函式在現存的類別中,而不需要去更動該類別的定義,也避免了重新編譯。

1 2 3 4 5 6 7 8 9
publicstaticclass IntExtensions {     publicstaticvoid PrintPlusOne(thisint x)     {        Console.WriteLine(x +1);     } } int foo =0; foo.PrintPlusOne();
## Generic Covariance and Contravariance

中文譯作協變與逆變這篇文章介紹得很詳細,節錄重點如下:

  • Base -> Derived 稱之逆變(弱型別->強型別)(使用 in 標記)
  • Derived -> Base 稱之協變(強型別->弱型別)(使用 out 標記)

因此,interface 與 delegate 有了協變與逆變性,許多方法都可以因此而提高重用性。

Reflection

根據維基百科上的解釋

Reflection is the ability of a computer program to examine and modify the structure and behavior of an object at runtime.

Reflection 的幫助下,很多執行期間的動作就不必寫死

1 2 3 4 5 6 7 8 9 10 11
class Program {     publicstaticint _number =7;     staticvoid Main()     {        Type type =[typeof](http://www.google.com/search?q=typeof+msdn.microsoft.com)(Program);        FieldInfo field = type.GetField("_number");        object temp = field.GetValue(null);        Console.WriteLine(temp);     } }
## ?? operator (C# 2.0)

大家可能已經很熟悉 Ternary/Conditional Operator,C# 還提供了一個類似的操作用來處理 null case 的賦值動作,直接看範例:

1 2 3 4 5
object nullObj =null; object obj =[new](http://www.google.com/search?q=new+msdn.microsoft.com)Object(); return nullObj ?? obj;// returns obj int? i =null;  // Declare a nullable int type. int j = i ??0;// Unless i is null, initialize j to i. Else (if i is null), initialize j to 0.
## 簡單的與 COM 元件互動

COM: Component Object Model

1 2 3
Word.Application wordApplication =[new](http://www.google.com/search?q=new+msdn.microsoft.com) Word.Application(){Visible =true}; wordApplication.Documents.Open(@"C:plant.docx", ReadOnly:true); excelObj.Cells[5, 5].Value="This is sample text";
## Roslyn (C# ??)

這是我個人最期待的功能:Compiler as a Service。一旦實現,未來大家可以寫出客製化的編譯器、除錯器、分析器,甚至可以讓 C# 執行 string evaluation 或整個變成動態語言!