好的設計是取得適當的折衷 - 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,就會如動態語言一樣,該變數的型別會在執行階段動態的變化。
1
2
3
| dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);
var calc = GetCalculator();// Anonymous Type (C# 3.0) |
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 |
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<100;++i, ++p)
*p = p[-1]+ p[-2];
for(int i=0; i<10;++i)
Console.WriteLine(fib[i]);
} |
Lambda Expression (C# 3.0)
Lambda 在函數語言與動態語言你可能已經很熟悉,C# 也順應潮流提供了此功能:
1
| listOfFoo.Where(x => x.Size>10); |
透過擴展方法,我們可以外掛一個函式在現存的類別中,而不需要去更動該類別的定義,也避免了重新編譯。
1
2
3
4
5
6
7
8
9
| publicstaticclass IntExtensions
{
publicstaticvoid PrintPlusOne(thisint x)
{
Console.WriteLine(x +1);
}
}
int foo =0;
foo.PrintPlusOne(); |
中文譯作協變與逆變,這篇文章介紹得很詳細,節錄重點如下:
- 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);
}
} |
大家可能已經很熟悉 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: 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"; |
這是我個人最期待的功能:Compiler as a Service。一旦實現,未來大家可以寫出客製化的編譯器、除錯器、分析器,甚至可以讓 C# 執行 string evaluation 或整個變成動態語言!