自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

C# 4何以成為微軟鋒利的刀——動態(tài)編程語言

開發(fā) 后端
作為微軟.NET平臺最重要的支柱,C#一直以一種不斷革新的面貌出現(xiàn),從C#1.0的委托到C# 4的動態(tài)編程語言。這也是C#成為微軟鋒利的刀的原因之一。

近幾年來,在TIOBE公司每個月發(fā)布的編程語言排行榜[1]中,C#總是能擠進(jìn)前10名,而在近10年的編程語言排行榜中,C#總體上呈現(xiàn)上升的趨勢。C#能取得這樣的成績,有很多因素在起作用,其中,它在語言特性上的銳意進(jìn)取讓人印象深刻(圖 1)。51CTO向您推薦《8月編程語言排行榜:微軟鋒利的刀C#

圖 1 C#各版本的創(chuàng)新點(diǎn)

2010年發(fā)布的C# 4,最大的創(chuàng)新點(diǎn)是擁有了動態(tài)編程語言的特性。

1 動態(tài)編程語言的中興

動態(tài)編程語言并非什么新鮮事物,早在面向?qū)ο缶幊陶Z言成為主流之前,人們就已經(jīng)使用動態(tài)編程語言來開發(fā)了。即使在Java、C#、C++等面向?qū)ο缶幊陶Z言繁榮興旺、大行于世的年代,動態(tài)編程語言也在“悄悄”地攻城掠地,占據(jù)了相當(dāng)?shù)拈_發(fā)領(lǐng)域,比如 JavaScript業(yè)已成為Web客戶端事實(shí)上的主流語言。

最近這幾年,動態(tài)編程語言變得日益流行,比如Python、Ruby都非常活躍,使用者眾多。

這里有一個問題,為什么我們需要在開發(fā)中應(yīng)用動態(tài)編程語言?與C#和Java這類已經(jīng)非常成熟且功能強(qiáng)大的靜態(tài)類型編程語言相比,動態(tài)編程語言有何優(yōu)勢?

 簡單地說,使用動態(tài)編程語言開發(fā)擁有以下的特性:

(1)支持REPL(Read-evaluate-print Loop:“讀入à執(zhí)行à輸出”循環(huán)迭代)的開發(fā)模式,整個過程簡潔明了,直指問題的核心。

 舉個簡單的例子,圖 2所示為使用IronPython[2]編程計(jì)算“1+2+……+100”的屏幕截圖,我們可以快速地輸入一段完成累加求和的代碼,然后馬上就可以看到結(jié)果:

圖 2 使用IronPython編程

如果使用C#開發(fā)就麻煩多了,您得先用Visual Studio創(chuàng)建一個項(xiàng)目,然后向其中添加一個類,在類中寫一個方法完成求和的功能,再編寫調(diào)用這一方法的代碼,編譯、排錯,最后才能得到所需的結(jié)果……

很明顯,對于那些短小的工作任務(wù)而言,動態(tài)編程語言所具備的這種REPL開發(fā)模式具有很大的吸引力。

(2)擴(kuò)展方便。用戶可以隨時對代碼進(jìn)行調(diào)整,需要什么功能直接往動態(tài)對象上“加”就是了,不要時又可以移除它們。而且這種修改可以馬上生效,并不需要像C#那樣必須先修改類型的定義和聲明,編譯之后新方法才可用。

換句話說:使用動態(tài)語言編程,不需要“重量級”的OOAD,整個開發(fā)過程迭代迅速而從不拖泥帶水。

(3)動態(tài)編程語言的類型解析是在運(yùn)行時完成的,可以省去許多不必要的類型轉(zhuǎn)換代碼,因此,與靜態(tài)編程語相比,動態(tài)編程語言寫的代碼往往更緊湊,量更少。

動態(tài)編程語言主要的弱點(diǎn)有兩個:

(1)代碼中的許多錯誤要等到運(yùn)行時才能發(fā)現(xiàn),而且需要特定的運(yùn)行環(huán)境支持,對其進(jìn)行測試不太方便,也不支持許多用于提升代碼質(zhì)量的各種軟件工程工具,因此不太適合于開發(fā)規(guī)模較大的、包容復(fù)雜處理邏輯的應(yīng)用系統(tǒng)。

(2)與靜態(tài)編程語言相比,動態(tài)編程語言編寫的程序性能較低。不過隨著計(jì)算機(jī)軟硬件技術(shù)的不斷進(jìn)步,比如多核CPU的廣泛應(yīng)用,動態(tài)編程語言引擎和運(yùn)行環(huán)境不斷地優(yōu)化,動態(tài)編程語言編寫的程序性能在不斷地提升,在特定的應(yīng)用場景下,甚至可以逼近靜態(tài)語言編寫的程序。

#p#

2 擁抱“動態(tài)編程”特性的C# 4

為了讓C#、Visual Basic等.NET編程語言能具備動態(tài)編程語言的特性,.NET 4.0引入了一個“DLR(Dynamic Language Runtime:動態(tài)語言運(yùn)行時)”(圖 3)。

圖 3 DLR:動態(tài)語言運(yùn)行時

DLR運(yùn)行于CLR之上,提供了一個動態(tài)語言的運(yùn)行環(huán)境,從而允許Python、Ruby等動態(tài)語言編寫的程序在.NET平臺上運(yùn)行,同時,現(xiàn)有的.NET靜態(tài)類型編程語言,比如C#和Visual Basic,也可以利用DLR而擁有一些動態(tài)編程語言的特性。

(1)使用C# 4編寫動態(tài)的代碼

 C# 4新增了一個dynamic關(guān)鍵字,可以用它來編寫“動態(tài)”的代碼。

例如,以下代碼創(chuàng)建了一個ExpandoObject對象(注意必須定義為dynamic):

  1. dynamic dynamicObj = new ExpandoObject(); 

這一對象的奇特之處在于,我們可以隨時給它增加新成員:

  1. dynamicObj.Value = 100; //添加字段  
  2. dynamicObj.Increment = new Action(() => dynamicObj.Value++); //添加方法 

這些動態(tài)添加的成員與普通的類成員用法一樣:

  1. for (int i = 0; i < 10; i++)  
  2. dynamicObj.Increment();//調(diào)用方法  
  3. Console.WriteLine("dynamicObj.Value={0}",dynamicObj.Value);//訪問字段 

ExpandoObject對象實(shí)現(xiàn)了IDictionary<string, object>接口,可看成是一個字典對象,所有動態(tài)添加的成員都是這個字典對象中的元素,這意味我們不僅可以添加新成員,還可以隨時移除不再需要的成員:

 

  1. //移除Increment方法  
  2. (dynamicObj as IDictionary<stringobject>).Remove("Increment"); 

 

方法移除之后,再嘗試訪問此方法將引發(fā)RuntimeBinderException異常。

(2)使用dynamic關(guān)鍵字簡化與COM組件交互的代碼

要在.NET這個“托管世界”里調(diào)用“非托管世界”中的COM組件,我們必須通過 “互操作程序集(Interop Assembly)”作為橋梁,“互操作程序集”定義了CLR類型與COM類型之間的對應(yīng)關(guān)系。

只要給.NET項(xiàng)目添加對“互操作程序集”的引用,就可以在.NET應(yīng)用程序中創(chuàng)建這一程序集所包容的各種類型的實(shí)例(即COM包裝器對象),對這些對象的方法調(diào)用(或?qū)ζ鋵傩缘拇嫒。晦D(zhuǎn)發(fā)給COM組件。

以調(diào)用Word為例,在C# 4.0之前您可能經(jīng)常需要編寫這樣的代碼:

  1. Object wordapp = new Word.Application();   //創(chuàng)建Word對象  
  2. Object fileName = “MyDoc.docx” ;//指定Word文檔  
  3. Object argu = System.Reflection.Missing.Value;  
  4. Word.Document doc = wordapp.Documents.Open(ref fileName, ref argu,  
  5. ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,  
  6. ref argu, ref argu, ref argu, ref argu, ref argu, ref argu,  
  7. ref argu, ref argu); 

上述對Open()方法的調(diào)用語句只能用“恐怖”一詞來形容,其原因是Word組件中的Open()方法定義了太多的參數(shù)。

C#4使用dynamic關(guān)鍵字,配合從Visual Basic中學(xué)來的“命名參數(shù)與可選參數(shù)”這兩個新語法特性,可以寫出更簡潔的代碼:

  1. dynamic wordapp = new Word.Application();  
  2. dynamic doc = wordapp.Documents.Open(FileName: “MyDoc.docx”); 

上述代碼中省去了用不著的參數(shù),并且可以去掉參數(shù)前的ref關(guān)鍵字。

當(dāng)上述代碼運(yùn)行時,DLR會使用反射技術(shù)將dynamic表達(dá)式“綁定(bind)”到COM互操作程序集中所包容的Word.Application代理對象。

(3)C# 4動態(tài)編程技術(shù)內(nèi)幕

C#4中所定義的dynamic變量可以引用以下類型的對象:

l 傳統(tǒng)的“靜態(tài)”的CLR對象。

l COM包裝器對象。前面已經(jīng)介紹了這方面的內(nèi)容。

l 實(shí)現(xiàn)了IDynamicMetaObjectProvider接口的“動態(tài)對象”,ExpandoObject就是這種類型對象的實(shí)例。

l 基于DLR實(shí)現(xiàn)的動態(tài)語言(比如IronRuby和IronPython)所創(chuàng)建的對象。

從C#程序員角度來看,所有這四種對象都是一樣的,都可用一個dynamic變量引用之,而DLR在程序運(yùn)行時動態(tài)地將方法調(diào)用和字段存取請求“綁定”到真正的對象上。

dynamic的功能是由DLR所支撐的,是C#編譯器與DLR分工合作的成果。

請看以下示例代碼:

  1. dynamic d = 100;  
  2. d++; 

C#編譯器在處理上述代碼時,它并不去檢查變量d是否可以支持自增操作,而是為其創(chuàng)建了一個CallSite<T>對象(<>p__Site1):

  1. private static class <Main>o__SiteContainer0 {  
  2. public static CallSite<Func<CallSite, objectobject>> <>p__Site1;  

中文MSDN將CallSite<T>譯為“動態(tài)(調(diào)用)站點(diǎn)”,它是DLR中的核心組件之一。

動態(tài)站點(diǎn)對象通過CallSite<T>.Create()方法創(chuàng)建, C#編譯器會為其指定一個派生自CallSiteBinder的對象(稱為“動態(tài)站點(diǎn)綁定對象”)作為其參數(shù)。

動態(tài)站點(diǎn)綁定對象是與具體語言相關(guān)的,比如IronPython和C#都有各自的動態(tài)站點(diǎn)綁定對象。

動態(tài)站點(diǎn)綁定對象的主要工作是將代碼中的動態(tài)表達(dá)式(本例中為d++)轉(zhuǎn)換為一棵“抽象語法樹(AST:Abstract Syntax Tree)”,這棵語法樹被稱為“DLR Tree”,是在.NET 3.5所引入的LINQ表達(dá)式樹的基礎(chǔ)上擴(kuò)充而來的,因此,有時又稱其為“表達(dá)式樹(Expression Tree)”

DLR在內(nèi)部調(diào)用此表達(dá)式樹的Compile()方法生成IL指令,得到一個可以被CLR所執(zhí)行的委托(在本例中其類型就是Func<CallSite, object, object>)。

動態(tài)調(diào)用站點(diǎn)對象(本例中為<>p__Site1)有一個Target屬性,它負(fù)責(zé)引用這一生成好的委托。

委托生成之后,動態(tài)表達(dá)式的執(zhí)行就體現(xiàn)為委托的執(zhí)行,其實(shí)參由C#編譯器直接“寫死”在IL代碼中。

簡化的代碼示意如下(通過Reflector得到,為便于閱讀,修改了變量名):

  1. object d = 100;  
  2. object CS$0$0000 = d;  
  3. if (<>p__Site1 == null)  
  4. <>p__Site1 = CallSite<Func<CallSite, objectobject>>.Create(……);  
  5. d = <>p__Site1.Target(<>p__Site1, CS$0$0000); 

上述類型推斷、方法綁定及IL代碼生成的工作都是在程序運(yùn)行時完成的。

(4)動態(tài)代碼很慢嗎?

動態(tài)編程語言易學(xué)易用,代碼緊湊,開發(fā)靈活,但性能則一直是它的“軟肋”。為了提升性能,DLR設(shè)計(jì)了一個三級緩存策略。

動態(tài)站點(diǎn)綁定對象會為動態(tài)調(diào)用表達(dá)式轉(zhuǎn)換而成的語法樹加上相應(yīng)的測試條件(稱為“test”),構(gòu)成一個“規(guī)則(Rule)”,這個規(guī)則可以用于判斷某個語法樹是否可用于特定的動態(tài)調(diào)用表達(dá)式。

舉個例子,請看以下這個動態(tài)表達(dá)式:

d1 + d2

如果在程序運(yùn)行時d1和d2都是int類型的整數(shù),則DLR生成的規(guī)則為:

  1. if( d1 is int && d2 is int//測試條件  
  2. return (int)d1+(int)d2; //語法樹 

DLR通過檢查規(guī)則中的“測試條件”,就可以知道某個動態(tài)表達(dá)式是否可以使用此規(guī)則所包容的語法樹。

“規(guī)則”是DLR緩存的主要對象。

前面介紹過的動態(tài)站點(diǎn)對象Target屬性所引用的委托是第一級緩存,它實(shí)現(xiàn)的處理邏輯是這樣的:

  1. //當(dāng)前處理規(guī)則,屬于第1級緩存  
  2. if( d1 is int && d2 is int//測試條件  
  3. return (int)d1+(int)d2; //滿足測試條件,直接返回一個表達(dá)式樹  
  4. //未命中,則在第2級、第3級緩存中查找,如果找到了,用找到的結(jié)果更新第1級緩存  
  5. return site.Update(site,d1,d2); 

如果3級緩存中都沒有命中的規(guī)則,則此動態(tài)站點(diǎn)所關(guān)聯(lián)的調(diào)用站點(diǎn)綁定對象會嘗試創(chuàng)建一個新的規(guī)則。如果創(chuàng)建新規(guī)則失敗,則由當(dāng)前編程語言(比如C#)所提供的默認(rèn)調(diào)用站點(diǎn)綁定對象決定如何處理,通常的作法是拋出一個異常。

當(dāng)前版本的DLR第2級緩存了10條規(guī)則,第3級則緩存了100條規(guī)則。

由于DLR自身設(shè)計(jì)了一個“規(guī)則”緩存系統(tǒng),又充分利用了CLR所提供的JIT緩存(因?yàn)樗袆討B(tài)調(diào)用代碼最終都會轉(zhuǎn)換為CLR可以執(zhí)行的IL指令,而CLR可以緩存這些代碼),使得動態(tài)代碼僅僅在第一次執(zhí)行時性能較差,后續(xù)的連續(xù)調(diào)用其性能可以逼近靜態(tài)代碼。

3 C# 4與動態(tài)語言的集成

由于幾乎所有的編程語言都可以使用抽象語法樹來表達(dá),因此,在理論上DLR支持無限多種編程語言間的互操作,在當(dāng)前版本中,可以實(shí)現(xiàn)C#/Visual Basic與IronPython和IronRuby的互操作,相信很快會出現(xiàn)其他動態(tài)編程語言的DLR實(shí)現(xiàn)。

一個有趣的地方是當(dāng)前基于DLR實(shí)現(xiàn)的動態(tài)編程語言都以“Iron”開頭,比如IronRuby和IronPython。IronPython的設(shè)計(jì)者、DLR的架構(gòu)設(shè)計(jì)師Jim Hugunin曾經(jīng)在微軟PDC 2008大會上解釋說主要是為了避免起一個“Python.NET”或“Python for .NET”之類“微軟味十足”的名字,才有了“IronPython”。他強(qiáng)調(diào):“Iron”系列動態(tài)語言將嚴(yán)格遵循動態(tài)語言自身的標(biāo)準(zhǔn)和規(guī)范,尊重這些動態(tài)語言已有的歷史和積累,不會引入一些僅限于.NET平臺的新語言特性,并且這些語言的.NET實(shí)現(xiàn)保持開源。與此同時,Jim Hugunin指出 “Iron”系列語言能很好地與.NET現(xiàn)有類庫、編程語言和工具集成,并且能“嵌入”到.NET宿主程序中。

(1)動態(tài)對象通訊協(xié)議

由于各種動態(tài)編程語言之間的特性相差極大,實(shí)現(xiàn)各語言間的互操作是個難題。為此DLR采取了一個聰明的策略,它不去嘗試設(shè)計(jì)一個“通用的類型系統(tǒng)”(CLR就是這么干的),而是設(shè)計(jì)了一個“通用的對象通訊協(xié)議”,規(guī)定所有需要互操作的動態(tài)對象必須實(shí)現(xiàn)IDynamicMetaObjectProvider接口,此接口定義了一個GetMetaObject()方法,接收一個語法樹對象作為參數(shù),向外界返回一個“動態(tài)元數(shù)據(jù)(DynamicMetaObject)”對象:

  1. DynamicMetaObject GetMetaObject(Expression parameter); 

DynamicMetaObject對象向外界提供了兩個重要屬性:Restrictions引用一組測試條件,Expression屬性則引用一個語法樹。這兩個屬性組合起來就是可供動態(tài)站點(diǎn)對象緩存的“規(guī)則(Rule)”。

DLR中的“動態(tài)站點(diǎn)綁定對象(CallSiteBinder)”獲取了DynamicMetaObject對象之后,它調(diào)用此對象所提供的各個方法創(chuàng)建“規(guī)則”,讓“動態(tài)站點(diǎn)對象(CallSite<T>)”的Target屬性引用它,完成動態(tài)綁定的工作。

(2)動態(tài)語言集成環(huán)境

為了方便地實(shí)現(xiàn)靜態(tài)編程語言與各種動態(tài)編程語言間的相互集成,DLR提供了一整套稱為“通用寄宿(Common Hosting)”的組件,其中包容ScriptRuntime、ScriptScope等類型。

下面我們以IronPython為例,介紹如何在C# 4開發(fā)的程序中集成動態(tài)編程語言代碼。

首先需要創(chuàng)建一個ScriptRuntime對象,它是一個最頂層的對象,用于在一個.NET應(yīng)用程序域中“嵌入”一個特定動態(tài)語言的運(yùn)行環(huán)境:

  1. ScriptRuntime pythonRuntime = Python.CreateRuntime(); 

接著需要創(chuàng)建一個ScriptEngine對象,它是動態(tài)語言代碼的執(zhí)行引擎:

  1. ScriptEngine engine = pythonRuntime.GetEngine("py"); 

ScriptScope對象類似于C#中的命名空間,其中可以通過定義一些變量向動態(tài)代碼傳入數(shù)據(jù),比如下述代碼將一個C# 創(chuàng)建的ExpandoObject對象傳給Python代碼:

  1. ScriptScope scope = pythonRuntime.CreateScope();  
  2. //C#創(chuàng)建動態(tài)對象  
  3.   dynamic expando = new ExpandoObject();  
  4. expando.Name = "JinXuLiang"; //動態(tài)添加一個字段  
  5.   //讓IronPython接收C#創(chuàng)建的Expando對象  
  6. scope.SetVariable("ExpandoObject", expando);  
  7. string pythonCode = "print ExpandoObject.Name";   
  8. //IronPython引擎執(zhí)行Python語句  
  9. engine.CreateScriptSourceFromString(pythonCode).Execute(scope);   

上述示例代碼是直接執(zhí)行Python代碼。在實(shí)際開發(fā)中,更常見的是直接執(zhí)行Python文件中的代碼,假設(shè)有一個Calculator.py文件,其中定義了一個Add函數(shù):

def Add(a,b):

return a+b

則以下C#代碼可以直接執(zhí)行之:

  1. ScriptRuntime pythonRuntime = Python.CreateRuntime();  
  2. dynamic pythonFile = pythonRuntime.UseFile("Calculator.py");  
  3. Console.WriteLine(pythonFile.Add(100, 200)); 

上述示例說明在DLR的支持之下,可以讓靜態(tài)編程語言使用動態(tài)語言所開發(fā)的庫,反過來,基于DLR實(shí)現(xiàn)的動態(tài)編程語言也能使用為靜態(tài)語言所設(shè)計(jì)的庫,比如標(biāo)準(zhǔn)的.NET基類庫。

這意味著兩點(diǎn):

(1)我們現(xiàn)在可以將“靜態(tài)”和“動態(tài)”編程語言組合起來,開發(fā)出一些具有高度交互性的應(yīng)用程序,使用靜態(tài)編程語言搭建系統(tǒng)框架,使用動態(tài)編程語言實(shí)現(xiàn)交互性,這是一個很值得注意的應(yīng)用領(lǐng)域。

(2)將來會出現(xiàn)一些“靜態(tài)”“動態(tài)”編程語言同時適用的庫,向?qū)崿F(xiàn)“無所不在的復(fù)用”目標(biāo)又前進(jìn)了一步。

Visual Studio 2010為新的.NET編程語言F#提供了專門的項(xiàng)目模板,但沒有為IronPython和IronRuby之類動態(tài)語言的開發(fā)提供支持,相信隨著動態(tài)語言在.NET平臺之上的應(yīng)用日趨廣泛,后繼版本的Visual Studio會直接支持動態(tài)語言的開發(fā)。

從C# 1.0~4.0所走過的路,可以很清晰地看到它的發(fā)展軌跡,得到這樣的一個結(jié)論:

未來的編程語言應(yīng)該是多范式的,具有高度的可組合性,在一個項(xiàng)目或產(chǎn)品中組合多個編程語言、使用多種編程范式會變得越來越普遍。

我們可以推斷C#的后繼版本將會在此條道路上越走越遠(yuǎn)……

原文標(biāo)題:C# 4動態(tài)編程新特性與DLR剖析

鏈接:http://www.cnblogs.com/bitfan/archive/2010/08/18/1802769.html

【編輯推薦】

  1. 詳解Visual C# 2010幾大新特征
  2. 詳解C#泛型特性及相關(guān)實(shí)例
  3. 詳解C#中相等運(yùn)算符重載可能造成的陷阱 
  4. 事與愿違 開發(fā)者希望看到的C# 4.0新特性
  5. C#歷史回顧及C# 4.0新特性一覽

 

責(zé)任編輯:彭凡 來源: 博客園
相關(guān)推薦

2010-08-02 16:44:31

2010-08-16 13:16:51

IT技術(shù)周刊

2021-08-27 10:50:30

編程語言開發(fā)Python

2009-02-03 09:33:26

動態(tài)類型動態(tài)編程C# 4.0

2009-08-14 15:54:12

C#編程語言

2010-07-28 15:18:10

編程語言函數(shù)式編程

2023-01-09 16:44:53

編程語言C++C

2009-09-02 10:58:02

C#動態(tài)數(shù)組

2022-07-11 10:53:55

語言Python

2018-03-11 08:30:32

Swift 編程語言C語言

2012-11-23 14:00:43

阿里云亞馬遜

2009-09-02 17:10:45

C#語言入門

2024-10-31 09:51:28

2025-03-26 02:55:00

2023-02-13 07:04:12

VBC#語言

2017-12-09 22:09:05

編程KotlinC語言

2025-02-14 08:13:05

AI技術(shù)開發(fā)

2009-08-13 17:04:09

C#語言C#程序

2024-09-04 08:09:54

2025-03-06 00:33:09

動態(tài)編程C#
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號