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