.NET 3.0其實只是PF, CF, WF和CardSpace組合在一起的一個擴充庫,.NET 2.0的核心部分沒有什麼變化,也不對應新的Visual Studio。.NET 3.5依舊沒有動到.NET 2.0的核心,其新增的核心組件是LINQ,為了實現LINQ,必須要在語言層面上進行改進,於是C#進化到了3.0版。
C#3.0依賴的是Visual Studio 2008,或者說是.NET 3.5 SDK中的C# Compiler,很多C# 3.0的特性是由編譯器完成的,C#3.0 + .NET2.0,也是非常有用的一個組合。從產品開發的角度來考慮,升級.NET Framework,是由一定的風險的,雖然從.NET 2.0到.NET 3.5,本質上只有擴充,但是從公司層級上來考慮,還是要謹慎對待。本文主要談一下C#3.0中純粹通過編譯器實現的新功能,也就是說可以用Visual Studio 2008編譯,並能運行於單純的.NET 2.0環境下的那部分。本文只是雜談,不涉及到如何使用這些功能,請參考MSDN或者其他文章。
1. lambda
lambda在其他語言裡中出現過,應用比較多的就是python,而C++也通過boost庫實現了一套類比lambda的機制。其實我有點不明白C# 2.0為什麼不直接引入lambda,而是先實現了anonymous method。可能有兩個方面的原因,時間限制和使用者教育。C# 3.0裡可以說沒有再使用anonymous method的必要了,lambda除了可以完全替代anonymous method外,還可以與編譯器配合產生Expression Tree,也就是LINQ的根本。關於LINQ和Expression Tree,在討論Query keywords會進一步涉及。
2. partial method
C#給大家主要的感覺是一門OO語言,一切都是對象,沒有全域變數和全域函數。但是作為一門工業語言,只支援一種Paradigm是不夠的。C# 1.0是OO的,2.0和3.0則增加了大量的functional programming和generative programming的功能,例如generic, lambda,partial class和partial method。雖然partial class和partial method對於團隊開發有一定的協助,但是其根本上還是為代碼自動產生服務的。partial method是否有用,很多程度上取決於設計師在代碼自動產生方面的設計,應用得當,可以提升團隊的開發效率。
有幾點限制:無傳回值(void),不能有out參數,隱式聲明為private(因此不能virtual),不能用於delegate。
3. 隱式類型推斷
首先明確一點,C#是強型別語言,對於局部變數的隱式類型推斷,僅僅是編譯器幫你發現變數的類型。對簡單類型(原生類型和非範型類型),用var是沒多大意義的,甚至是不能鼓勵的,應該使用顯式類型和介面。隨著範型引入.NET,對象的類型名會變得越來越長,如果看過boost裡的lambda或者tuple的實現,就會理解範型帶來的長類型名。LINQ的引入又加大了這種趨勢,隱式類型推斷在保證強型別的前提下,大大提高了代碼的可讀性和程式員的開發效率。
4. 匿名型別
匿名型別依舊是強型別,同樣其最直接的用途也是LINQ。具備同樣簽名特徵的匿名型別在不同的assembly是反覆產生的,因此如果有明確的業務定義時,不建議使用匿名型別。LINQ返回的臨時結果,或者實現特定介面的局部代碼,使用匿名型別可以減少名字空間汙染,提高可讀性,降低出錯幾率。
5. 對象初始化和集合初始化
提升代碼可讀性和簡潔的功能,不多介紹了。
6. 擴充方法
動態語言裡有類型擴充的機制,例如Python裡,類型也是對象,可以直接擴充類的方法,JavaScript通過Prototype擴充。C# 3.0對於類功能擴充的實現還是非常巧妙的,利用編譯器實現,類似C++中的Templete也是由前置處理器完成的。不違反開放封閉原則,可以實現比較好的代碼可讀性。
7. 自動實作屬性
把之前IDE實現的功能交給編譯器實現了。不同於C/C++,有很多的編譯器實現,C#的編譯器控制在Microsoft手中,這樣就有了編譯器上改進的便捷。很多功能通過類庫實現是非常複雜的,比如boost的lambda,而且可讀性也較差,然而通過編譯器或者前置處理器(AspectJ),可以實現更好的效果。
有幾點需要注意的,必須同時提供get和set,不能應用Attribute
8. 查詢關鍵字
query keywords是為配合LINQ而產生的,這個是C# 3.0的功能中必須依賴.NET3.5的。編譯器將query keyword產生為lambda和Expression Tree,這部分是可以編譯器完成的,但是Expression Tree裡的物件類型,都是在System.Core.dll中定義的,脫離了.NET 3.5的環境無法使用。當然也可以將幾個dll直接拷貝到.NET的目標機器上運行,但是穩定性沒有保證。
最後總結一下,工業層級的語言總是會不斷演化的,C# 3.0, Python 3, C++ TR1, C99, PHP 5這些版本都帶來了一些新的功能,這些功能到底有沒有用?如果僅以功能實現為目標,那麼用處不大,但是如果追求直觀,優雅的設計,追求代碼簡潔可讀,進而將Coding當成一門藝術時,語言的每個改進都帶來的更多的可能性。駕馭這些新功能是需要一定的功力的,其前提是擁抱變化,欣而接受變化。如果自滿於功能已實現,受限於自己的知識結構和設計習慣,是享受不到新功能帶來的可能性的。