終於靜下心來仔細聽了一遍Anders Hejlsberg(Visual Studio組的TECHNICAL FELLOW,C#的設計者之一)在PDC08上講的“The Future of C#”(http://channel9.msdn.com/pdc2008/TL16/)。
回顧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:
- 視頻: http://channel9.msdn.com/pdc2008/TL16/
- PPT:http://mschnlnine.vo.llnwd.net/d1/pdc08/PPTX/TL16.pptx
- 範例程式碼及文檔(New features in C# 4.0):http://code.msdn.microsoft.com/csharpfuture