轉(zhuǎn)帖|其它|編輯:郝浩|2010-06-10 09:38:44.000|閱讀 757 次
概述:靜態(tài)類型檢查的引入是編程語言史上一個(gè)重要的里程碑。在二十世紀(jì)七十年代,Pascal 和 C 等語言開始執(zhí)行靜態(tài)類型和強(qiáng)類型檢查。有了靜態(tài)類型檢查,對(duì)于任何無法傳遞相應(yīng)類型方法參數(shù)的調(diào)用,編譯器都將產(chǎn)生錯(cuò)誤。同樣,如果您試圖調(diào)用類型實(shí)例中不存在的方法,編譯器也應(yīng)該會(huì)產(chǎn)生錯(cuò)誤。
# 界面/圖表報(bào)表/文檔/IDE等千款熱門軟控件火熱銷售中 >>
靜態(tài)類型檢查的引入是編程語言史上一個(gè)重要的里程碑。在二十世紀(jì)七十年代,Pascal 和 C 等語言開始執(zhí)行靜態(tài)類型和強(qiáng)類型檢查。有了靜態(tài)類型檢查,對(duì)于任何無法傳遞相應(yīng)類型方法參數(shù)的調(diào)用,編譯器都將產(chǎn)生錯(cuò)誤。同樣,如果您試圖調(diào)用類型實(shí)例中不存在的方法,編譯器也應(yīng)該會(huì)產(chǎn)生錯(cuò)誤。
推進(jìn)動(dòng)態(tài)類型檢查這一相對(duì)應(yīng)方法的其他語言在過去幾年有所發(fā)展。動(dòng)態(tài)類型檢查否定了以下這一觀點(diǎn):即變量類型是在編譯時(shí)靜態(tài)確定的,當(dāng)變量在作用域內(nèi)時(shí)應(yīng)該永遠(yuǎn)不變。不過請(qǐng)注意,動(dòng)態(tài)類型檢查并非認(rèn)為各個(gè)類型都是相同的,可以對(duì)類型進(jìn)行自由組合。例如,即使使用動(dòng)態(tài)類型檢查,您仍不能為整數(shù)添加布爾值。動(dòng)態(tài)類型檢查的不同之處在于,檢查是發(fā)生在程序執(zhí)行時(shí),而不是編譯時(shí)。
靜態(tài)類型化與動(dòng)態(tài)類型化
Visual Studio 2010 和 C# 4.0 提供了新的動(dòng)態(tài)關(guān)鍵字,能夠在傳統(tǒng)上采用靜態(tài)類型化的語言中實(shí)現(xiàn)動(dòng)態(tài)類型化。不過,在深入了解 C#4.0 的動(dòng)態(tài)方面之前,我們需要記錄一些基本術(shù)語。
讓我們定義某個(gè)變量,作為只能采用特定類型數(shù)值的存儲(chǔ)位置。下一步,讓我們說明靜態(tài)類型化語言的四個(gè)基本屬性:
每個(gè)表達(dá)式都屬于已在編譯時(shí)確定的類型。
變量只能屬于已在編譯時(shí)確定的類型。
編譯器保證在將表達(dá)式指定給變量時(shí)采用的類型限制滿足對(duì)變量的限制。
重載解析等語義分析任務(wù)發(fā)生在編譯時(shí),其結(jié)果會(huì)輸入到程序集。
動(dòng)態(tài)語言的屬性正相反。每個(gè)表達(dá)式和每個(gè)變量的類型并未在編譯時(shí)就確定。存儲(chǔ)限制(如果有的話)是在運(yùn)行時(shí)進(jìn)行檢查,而在編譯時(shí)會(huì)被忽略。語義分析也只發(fā)生在運(yùn)行時(shí)。
靜態(tài)類型化語言確實(shí)可以實(shí)現(xiàn)某些操作的動(dòng)態(tài)化。它們提供了轉(zhuǎn)換運(yùn)算符,供您作為運(yùn)行時(shí)操作嘗試進(jìn)行類型轉(zhuǎn)換。程序代碼中已加入了轉(zhuǎn)換功能,您可以將轉(zhuǎn)換運(yùn)算符所表達(dá)的語義總結(jié)為“動(dòng)態(tài)檢查此轉(zhuǎn)換在運(yùn)行時(shí)的有效性。”
不過,就動(dòng)態(tài)和靜態(tài)(也可以說是強(qiáng)和弱)等屬性而言:目前與應(yīng)用到整個(gè)編程語言相比,應(yīng)用到語言的各個(gè)功能效果更好。
讓我們大致考察一下 Python 和 PHP。這兩者都是動(dòng)態(tài)語言,可供您使用變量,并提供了運(yùn)行時(shí)環(huán)境,可獲知實(shí)際存儲(chǔ)在其中的類型。不過如果使用 PHP,您可以在同一作用域的同一變量中同時(shí)存儲(chǔ)整數(shù)和字符串等等。從這一意義上講,PHP(類似于 JavaScript)是一種弱類型化的動(dòng)態(tài)語言。
與之相對(duì),Python 只會(huì)給您一次機(jī)會(huì)來設(shè)置變量類型,這使得它更貼近強(qiáng)類型化。您可以對(duì)變量動(dòng)態(tài)指定類型,并由運(yùn)行時(shí)環(huán)境從指定值推斷其類型。不過,在此之后,您不能在此變量中存儲(chǔ)任何不當(dāng)類型的值。
C# 中的動(dòng)態(tài)類型
C#4.0 所擁有的功能使其兼具動(dòng)態(tài)和靜態(tài)以及弱類型化和強(qiáng)類型化這兩種特點(diǎn)。C# 原本屬于靜態(tài)類型化語言,但在使用動(dòng)態(tài)關(guān)鍵字的任何上下文中,它都可以成為動(dòng)態(tài)類型化語言,如下所示:
dynamic number = 10; Console.WriteLine(number); |
而且因?yàn)閯?dòng)態(tài)關(guān)鍵字是上下文關(guān)鍵字,而不是保留關(guān)鍵字,如果您有現(xiàn)有變量或由方法命名的動(dòng)態(tài)關(guān)鍵字,這一點(diǎn)仍然成立。
請(qǐng)注意,C#4.0 不強(qiáng)制您使用動(dòng)態(tài)關(guān)鍵字,就像 C#3.0 不強(qiáng)制您使用 var、lambda 或?qū)ο蟪跏贾狄粯印#4.0 提供了新的動(dòng)態(tài)關(guān)鍵字,專門用于簡(jiǎn)化對(duì)一些眾所周知的情形的處理。這種語言盡管有能力以更有效的方式與動(dòng)態(tài)對(duì)象互動(dòng),從本質(zhì)上講它仍然屬于靜態(tài)類型化語言。
為什么要使用動(dòng)態(tài)對(duì)象?首先,您可能不知道正在處理的對(duì)象的類型。對(duì)于如何確定給定變量的靜態(tài)類型,您可能有線索,但卻拿不準(zhǔn):這種情況非常常見,例如當(dāng)您處理 COM 對(duì)象或使用反射來抓取實(shí)例時(shí),就會(huì)發(fā)生這種情況。這種情況下即可使用動(dòng)態(tài)關(guān)鍵字來簡(jiǎn)化某些操作。采用動(dòng)態(tài)方式書寫的代碼更易于讀寫,這樣便于理解與維護(hù)應(yīng)用程序。
其次,您的對(duì)象從本質(zhì)上講可能就是變化的。您處理的可能正是 IronPython 和 IronRuby 等動(dòng)態(tài)編程環(huán)境所生成的對(duì)象。不過,您還可以使用此功能來處理 HTML DOM 對(duì)象(這取決于 expando 屬性)和在創(chuàng)建時(shí)專門指定了動(dòng)態(tài)屬性的 Microsoft .net Framework 4 對(duì)象。
使用動(dòng)態(tài)變量
一定要理解以下概念:在 C# 類型系統(tǒng)中,動(dòng)態(tài)是一種類型。動(dòng)態(tài)的含義非常特殊,但它絕對(duì)是一種類型,一定要將它看作類型。您可以將動(dòng)態(tài)指定為自己所聲明變量的類型、集合中的項(xiàng)目類型或某方法的返回值,還可以將動(dòng)態(tài)用作方法參數(shù)的類型;不過,您不可以將動(dòng)態(tài)用于運(yùn)算符類型,也不可以將其用作類的基類型。
下面的代碼說明了如何在方法主體中聲明動(dòng)態(tài)變量:
public void Execute() { dynamic calc = GetCalculator(); int result = calc.Sum(1, 1); } |
如果您充分了解由 GetCalculator 方法返回的對(duì)象類型,您可以聲明該類型的變量 calc,也可以作為 var 聲明變量,以供編譯器了解具體細(xì)節(jié)。不過,使用 var 或顯式靜態(tài)類型,要求您確定 GetCalculator 所返回類型的約定上存在 Sum 方法。如果該方法不存在,您就會(huì)收到編譯器錯(cuò)誤。
采用動(dòng)態(tài)方法,您可以推遲到執(zhí)行時(shí)再確定表達(dá)式是否正確。只要方法 Sum 存在于變量 calc 所存儲(chǔ)的類型中,代碼即會(huì)得到編譯,并在運(yùn)行時(shí)得到解析。
您還可以使用此關(guān)鍵字在類上定義屬性。這樣做,您就可以用公共、受保護(hù)甚至靜態(tài)等所需的任何可見性修飾符修飾此成員。
圖 1 顯示了動(dòng)態(tài)關(guān)鍵字的通用性。主程序包含了根據(jù)某函數(shù)調(diào)用的返回值進(jìn)行實(shí)例化的動(dòng)態(tài)變量。因?yàn)榇撕瘮?shù)會(huì)接收并返回動(dòng)態(tài)對(duì)象,所以即便沒有實(shí)現(xiàn)實(shí)例化,也無關(guān)緊要。在這個(gè)例子中,您傳遞一個(gè)數(shù)字,然后嘗試在此函數(shù)中對(duì)它進(jìn)行 double 操作,看看發(fā)生什么,會(huì)很有趣。
圖 1 在函數(shù)的簽名中使用動(dòng)態(tài)屬性
class Program { static void Main(string[] args) { // The dynamic variable gets the return // value of a function call and outputs it. dynamic x = DoubleIt(2); Console.WriteLine(x); // Stop and wait Console.WriteLine(“Press any key”); Console.ReadLine(); } // The function receives and returns a dynamic object private static dynamic DoubleIt(dynamic p) { // Attempt to "double" the argument whatever // that happens to produce return p + p; } } |
如果您輸入數(shù)值 2,然后運(yùn)行此代碼,您將得到數(shù)值 4;而如果您作為字符串輸入 2,您會(huì)得到 22。此函數(shù)會(huì)根據(jù)操作數(shù)的運(yùn)行時(shí)類型對(duì) + 運(yùn)算符進(jìn)行動(dòng)態(tài)解析。如果您將類型更改為 System.Object,會(huì)收到編譯錯(cuò)誤,原因即在于 + 運(yùn)算符未在 System.Object 上進(jìn)行定義。動(dòng)態(tài)關(guān)鍵字能使不可能變成可能。
動(dòng)態(tài)與 System.Object
直到 .net Framework 4,還是只能求助于通用基類,才能使方法可根據(jù)不同的情況返回不同的類型。您可能已經(jīng)通過求助于 System.Object 解決了此問題。返回 System.Object 的函數(shù)會(huì)向調(diào)用者提供可以轉(zhuǎn)換幾乎任何內(nèi)容的實(shí)例。這種情況下,為什么還說使用動(dòng)態(tài)的效果要好于使用 System.Object 呢?
在 C# 4 中,被聲明為動(dòng)態(tài)的變量后面的實(shí)際類型是在運(yùn)行時(shí)加以解析,編譯器會(huì)認(rèn)定:聲明為動(dòng)態(tài)的變量中的對(duì)象完全支持任何操作。也就是說,您編寫的代碼完全可以調(diào)用您認(rèn)為會(huì)在運(yùn)行時(shí)出現(xiàn)的對(duì)象上的方法,如下所示:
dynamic p = GetSomeReturnValue(); p.DoSomething(); |
在 C# 4.0 中,編譯器不會(huì)對(duì)該代碼報(bào)錯(cuò)。而使用 System.Object 的類似代碼將無法進(jìn)行編譯,為了解決這一問題,需要您自己采取一定措施,如進(jìn)行反射或冒一定風(fēng)險(xiǎn)進(jìn)行轉(zhuǎn)換。
var 與動(dòng)態(tài)
var 與動(dòng)態(tài)關(guān)鍵字只是表面上相似。var 認(rèn)為,此變量的類型必須被設(shè)置為初始值設(shè)定項(xiàng)的編譯時(shí)類型。
但是,動(dòng)態(tài)意味著此變量的類型可以是 C#4.0 中可用的任何動(dòng)態(tài)類型。動(dòng)態(tài)與 var 的最終含義基本上是相反的。var 講的是加強(qiáng)與改進(jìn)靜態(tài)類型化。其目標(biāo)是確保編譯器可根據(jù)初始值設(shè)定項(xiàng)返回的確切類型推斷變量類型。
動(dòng)態(tài)關(guān)鍵字的目標(biāo)是完全避免靜態(tài)類型化。用于變量聲明中時(shí),動(dòng)態(tài)會(huì)指示編譯器完全停止求解變量類型。該類型需要采納它在運(yùn)行時(shí)的類型。而使用 var 時(shí),您的代碼會(huì)采用靜態(tài)類型化方式,其結(jié)果與選擇在變量聲明中使用顯式類型的經(jīng)典方式一致。
兩類關(guān)鍵字之間的另一區(qū)別是:var 只能出現(xiàn)在局部變量聲明中。您不能使用 var 來定義類屬性,也不能用它來指定返回值或函數(shù)的參數(shù)。
作為一名開發(fā)人員,如果預(yù)計(jì)變量包含不確定類型的對(duì)象,您就應(yīng)該使用動(dòng)態(tài)關(guān)鍵字,如對(duì)象從 COM 或 DOM API 返回;從動(dòng)態(tài)語言(如 IronRuby)獲得;從反射獲得;從使用新擴(kuò)展功能在 C# 4.0 中動(dòng)態(tài)構(gòu)建的對(duì)象中獲得。
不過,動(dòng)態(tài)類型不是繞過類型檢查,只是將其全部移至運(yùn)行時(shí)。如果在運(yùn)行時(shí)發(fā)現(xiàn)不兼容的類型,則引出異常。
本站文章除注明轉(zhuǎn)載外,均為本站原創(chuàng)或翻譯。歡迎任何形式的轉(zhuǎn)載,但請(qǐng)務(wù)必注明出處、不得修改原文相關(guān)鏈接,如果存在內(nèi)容上的異議請(qǐng)郵件反饋至chenjj@fc6vip.cn
文章轉(zhuǎn)載自:網(wǎng)絡(luò)轉(zhuǎn)載