C# 4.0新特性一覽

回顧C#發展的歷史,C#1.0徹底是模仿Java,並保留了C/C++的一些特性如struct,新學者很容易上手;C#2.0加入了泛型,也與Java1.5的泛型一模一樣;C#3.0加入了一堆語法糖,並在沒有修改CLR的狀況下引入了Linq,簡直是神來之筆,雖然不少項目出於各類各樣如性能之類的緣由沒有采用,但很是適合小型程序的快速開發,減輕了程序員的工做量,也提升了代碼的可讀性;C#4.0增長了動態語言的特性,從裏面能夠看到不少javascript、python這些動態語言的影子。雖然愈來愈偏離靜態語言的道路,但從另外一個角度來講,這些特性也都是爲了提升程序員的生產力。至於被接受與否,仍是讓時間來講話吧。
PS:這裏面還有一點版本號的小插曲——VS2008所對應的.Net Framework是3.5,C#是3.0,CLR是2.0,及其混亂,MS終於下決心在VS2010中把這三個版本號都統一成了4.0,因而CLR3不知所終……

Dynamically Typed Object
C#4.0加入了dynamic關鍵字,能夠申明一個變量的static類型爲dynamic(有點繞口)。
在3.0及以前,若是你不知道一個變量的類型,而要去調用它的一個方法,通常會用到反射:
object calc = GetCalculator();
Type calcType = calc.GetType();
object res = calcType.InvokeMember( "Add",
BindingFlags.InvokeMethod, null,
new object[] { 10, 20 });
int sum = Convert.ToInt32(res);

有了dynamic,就能夠把上面代碼簡化爲:
dynamic calc = GetCalculator();
int sum = calc.Add(10, 20);
使用dynamic的好處在於,能夠不去關心對象是來源於COM, IronPython, HTML DOM或者反射,只要知道有什麼方法能夠調用就能夠了,剩下的工做能夠留給runtime。下面是調用IronPython類的例子:
ScriptRuntime py = Python.CreateRuntime();
dynamic helloworld = py.UseFile( "helloworld.py");
Console.WriteLine( "helloworld.py loaded!");

dynamic也能夠用在變量的傳遞中,runtime會自動選擇一個最匹配的overload方法。
這裏有一個demo:把一段javascript代碼拷到C#文件中,將var改爲dynamic,function改爲void,再改一下構造函數的調用方式(new type()改成win.New.type()),去掉javascript中的win.前綴(由於這已是C#的方法了),就能夠直接運行了。
dynamic的實現是基於IDynamicObject接口和DynamicObject抽象類。而動態方法、屬性的調用都被轉爲了GetMember、Invoke等方法的調用。
public abstract class DynamicObject : IDynamicObject
{
public virtual object GetMember(GetMemberBinder info);
public virtual object SetMember(SetMemberBinder info, object value);
public virtual object DeleteMember(DeleteMemberBinder info);     public virtual object UnaryOperation(UnaryOperationBinder info);
public virtual object BinaryOperation(BinaryOperationBinder info, object arg);
public virtual object Convert(ConvertBinder info);     public virtual object Invoke(InvokeBinder info, object[] args);
public virtual object InvokeMember(InvokeMemberBinder info, object[] args);
public virtual object CreateInstance(CreateInstanceBinder info, object[] args);     public virtual object GetIndex(GetIndexBinder info, object[] indices);
public virtual object SetIndex(SetIndexBinder info, object[] indices, object value);
public virtual object DeleteIndex(DeleteIndexBinder info, object[] indices);     public MetaObject IDynamicObject.GetMetaObject();
}
Named and optional parameters
這彷佛不是什麼很難實現或很新穎的特性,只要編譯器的支持就能夠(VB很早就支持了)。估計加入的緣由是羣衆的呼聲過高了。
帶有可選參數方法的聲明:
public StreamReader OpenTextFile(
string path,
Encoding encoding = null,
bool detectEncoding = true,
int bufferSize = 1024);
命名參數必須在最後使用:
OpenTextFile( "foo.txt", Encoding.UTF8, bufferSize: 4096);
順序不限:
OpenTextFile(bufferSize: 4096, path: "foo.txt", detectEncoding: false);
Improved COM Interoperability
在C#中在調用COM對象如office對象時,常常須要寫一堆沒必要要的參數:
object fileName = "Test.docx";
object missing    = System.Reflection.Missing.Value;
doc.SaveAs( ref fileName,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing,
ref missing, ref missing, ref missing);
4.0中就能夠直接寫成:
doc.SaveAs( "Test.docx");
C#4.0對COM交互作了下面幾方面的改進:
Automatic object -> dynamic mapping    
Optional and named parameters    
Indexed properties    
Optional 「 ref」 modifier    
Interop type embedding (「No PIA」)

對第1點和第5點的簡單解釋以下:
在COM調用中,不少輸入輸出類型都是object,這樣就必須知道返回對象的確切類型,強制轉換後才能夠調用相應的方法。在4.0中有了dynamic的支持,就能夠在導入這些COM接口時將變量定義爲dynamic而不是object,省掉了強制類型轉換。
PIA(Primary Interop Assemblies)是根據COM API生成的.Net Assembly,通常體積比較大。在4.0中運行時不須要PIA的存在,編譯器會判斷你的程序具體使用了哪一部分COM API,只把這部分用PIA包裝,直接加入到你本身程序的Assembly裏面。
Co- and Contra-Variance
實在是不知道怎麼翻譯這兩個詞。
(感謝Ariex,徐少俠,AlexChen的提示,應翻譯爲協變和逆變, http://msdn.microsoft.com/zh-cn/library/ms173174(VS.80).aspx
在C#中,下面的類型轉換是非法的:
IList< string> strings = new List< string>();
IList< object> objects = strings;
由於你有可能會這樣作,而編譯器的靜態檢查沒法查出錯誤:
objects[0] = 5;
string s = strings[0];
4.0中在聲明generic的Interface及Delegate時能夠加in及out關鍵字,如:
public interface IEnumerable< out T> : IEnumerable
{
IEnumerator<T> GetEnumerator();
}
public interface IEnumerator< out T> : IEnumerator
{
bool MoveNext();
T Current { get; }
}
public interface IComparer< in T>
{
public int Compare(T left, T right);
}
out關鍵字的意思是說IEnumerable<T>中T只會被用在輸出中,值不會被改變。這樣將IEnumerable<string>轉爲IEnumerable<object>類型就是安全的。
in的意思正好相反,是說IComparer<T>中的T只會被用在輸入中,這樣就能夠將IComparer<object>安全的轉爲IComparer<string>類型。
前者被稱爲Co-Variance, 後者就是Contra-Variance。
.Net4.0中使用out/in聲明的Interface:
System.Collections.Generic.IEnumerable< out T>
System.Collections.Generic.IEnumerator< out T>
System.Linq.IQueryable< out T>
System.Collections.Generic.IComparer< in T>
System.Collections.Generic.IEqualityComparer< in T>
System.IComparable< in T>

Delegate:

System.Func< in T, …, out R>
System.Action< in T, …>
System.Predicate< in T>
System.Comparison< in T>
System.EventHandler< in T>
Compiler as a Service
4.0中增長了與編譯器相關的API,這樣就能夠將字符串做爲代碼動態編譯執行,跟javascript好像。
Video的最後,Anders作了一個很酷的demo,大概只用了二三十行代碼,就實現了在控制檯中直接執行C#語句,定義並調用函數,動態建立windows form,添加button等功能,看起來徹底不遜色於Python,Ruby之類語言的控制檯。
沉寂了n年以後,CLR終於要出新版本了,這回Jeffrey Richter大俠沒有藉口不出新版的CLR via C#了吧:)
Reference:
相關文章
相關標籤/搜索