C#歷史回顧及C# 4.0新特性一覽
C#歷史回顧
回顧C(jī)#發(fā)展的歷史,C# 1.0完全是模仿Java,并保留了C/C++的一些特性如struct,新學(xué)者很容易上手;C# 2.0加入了泛型,也與Java1.5的泛型如出一轍;C# 3.0加入了一堆語法糖,并在沒有修改CLR的情況下引入了Linq,簡直是神來之筆,雖然很多項(xiàng)目出于各種各樣如性能之類的原因沒有采用,但非常適合小型程序的快速開發(fā),減輕了程序員的工作量,也提高了代碼的可讀性;C# 4.0增加了動態(tài)語言的特性,從里面可以看到很多javascript、python這些動態(tài)語言的影子。雖然越來越偏離靜態(tài)語言的道路,但從另一個角度來說,這些特性也都是為了提高程序員的生產(chǎn)力。至于被接受與否,還是讓時間來說話吧。
PS:這里面還有一點(diǎn)版本號的小插曲——VS2008所對應(yīng)的.Net Framework是3.5,C#是3.0,CLR是2.0,及其混亂,MS終于下決心在VS2010中把這三個版本號都統(tǒng)一成了4.0,于是CLR3不知所終……
C# 4.0新特性:Dynamically Typed Object
C#4.0加入了dynamic關(guān)鍵字,可以申明一個變量的static類型為dynamic(有點(diǎn)繞口)。
在3.0及之前,如果你不知道一個變量的類型,而要去調(diào)用它的一個方法,一般會用到反射:
- 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的好處在于,可以不去關(guān)心對象是來源于COM, IronPython, HTML DOM或者反射,只要知道有什么方法可以調(diào)用就可以了,剩下的工作可以留給runtime。下面是調(diào)用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,再改一下構(gòu)造函數(shù)的調(diào)用方式(new type()改為win.New.type()),去掉javascript中的win.前綴(因?yàn)檫@已經(jīng)是C#的方法了),就可以直接運(yùn)行了。
dynamic的實(shí)現(xiàn)是基于IDynamicObject接口和DynamicObject抽象類。而動態(tài)方法、屬性的調(diào)用都被轉(zhuǎn)為了GetMember、Invoke等方法的調(diào)用。
- 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();
- }
C# 4.0新特性:Named and optional parameters
這似乎不是什么很難實(shí)現(xiàn)或很新穎的特性,只要編譯器的支持就可以(VB很早就支持了)。估計(jì)加入的原因是群眾的呼聲太高了。
帶有可選參數(shù)方法的聲明:
- public StreamReader OpenTextFile(
- string path,
- Encoding encoding = null,
- bool detectEncoding = true,
- int bufferSize = 1024);
命名參數(shù)必須在最后使用:
- OpenTextFile("foo.txt", Encoding.UTF8, bufferSize: 4096);
順序不限:
- OpenTextFile(bufferSize: 4096, path: "foo.txt", detectEncoding: false);
Improved COM Interoperability
在C#中在調(diào)用COM對象如office對象時,經(jīng)常需要寫一堆不必要的參數(shù):
- 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交互做了下面幾方面的改進(jìn):
- Automatic object -> dynamic mapping
- Optional and named parameters
- Indexed properties
- Optional “ref” modifier
- Interop type embedding (“No PIA”)
對第1點(diǎn)和第5點(diǎn)的簡單解釋如下:
在COM調(diào)用中,很多輸入輸出類型都是object,這樣就必須知道返回對象的確切類型,強(qiáng)制轉(zhuǎn)換后才可以調(diào)用相應(yīng)的方法。在4.0中有了dynamic的支持,就可以在導(dǎo)入這些COM接口時將變量定義為dynamic而不是object,省掉了強(qiáng)制類型轉(zhuǎn)換。
PIA(Primary Interop Assemblies)是根據(jù)COM API生成的.Net Assembly,一般體積比較大。在4.0中運(yùn)行時不需要PIA的存在,編譯器會判斷你的程序具體使用了哪一部分COM API,只把這部分用PIA包裝,直接加入到你自己程序的Assembly里面。
C# 4.0新特性:Co- and Contra-Variance
實(shí)在是不知道怎么翻譯這兩個詞。
(感謝Ariex,徐少俠,AlexChen的提示,應(yīng)翻譯為協(xié)變和逆變,http://msdn.microsoft.com/zh-cn/library/ms173174(VS.80).aspx)
在C#中,下面的類型轉(zhuǎn)換是非法的:
- IList< string> strings = new List< string>();
- IList< object> objects = strings;
因?yàn)槟阌锌赡軙@樣做,而編譯器的靜態(tài)檢查無法查出錯誤:
- objects[0] = 5;
- string s = strings[0];
4.0中在聲明generic的Interface及Delegate時可以加in及out關(guān)鍵字,如:
- 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關(guān)鍵字的意思是說IEnumerable< T>中T只會被用在輸出中,值不會被改變。這樣將IEnumerable< string>轉(zhuǎn)為IEnumerable< object>類型就是安全的。
in的意思正好相反,是說IComparer< T>中的T只會被用在輸入中,這樣就可以將IComparer< object>安全的轉(zhuǎn)為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>
C# 4.0新特性:Compiler as a Service
4.0中增加了與編譯器相關(guān)的API,這樣就可以將字符串作為代碼動態(tài)編譯執(zhí)行,跟javascript好像。
Video的最后,Anders做了一個很酷的demo,大概只用了二三十行代碼,就實(shí)現(xiàn)了在控制臺中直接執(zhí)行C#語句,定義并調(diào)用函數(shù),動態(tài)創(chuàng)建windows form,添加button等功能,看起來完全不遜色于Python,Ruby之類語言的控制臺。
沉寂了n年之后,CLR終于要出新版本了,這回Jeffrey Richter大俠沒有借口不出新版的CLR via C#了吧:)
本文來自張國良的專欄《c# 4.0新特性一覽》
【編輯推薦】