CLR via C# 之管中窥豹(一)
記得剛畢業那會,看過一陣CLR via C#,由于書中知識對于我來說過于深奧,最終只得放棄。而今重新拾起此書并結合工作中的一些經驗,偶有小感就寫成隨筆分享給大家,便于共同探討,也能幫助我成長。
執行程序集的代碼
前幾天組里有個測試找我幫他們看個自動化測試的用例,該用例從某一天就一直拋出加載程序集失敗的異常。在這里我用一個場景去模擬當時的情形 ,有這么一個測試用例:我們測試Visual Studio創建工程(隨機創建Silverlight或者WPF),并為新建的工程添加一個按鈕。我們需要為WPF和Silverlight創建相應的按鈕,但是我們把這兩種按鈕添加的邏輯放到一個方法里面,并通過一個布爾值去區分不同的工程。添加按鈕邏輯的樣例代碼如下:
1 public void AddButton(bool isSiverlight) 2 { 3 if (isSiverlight) 4 { 5 Silverlight.System.Windows.Controls.Button button = new Silverlight.System.Windows.Controls.Button(); 6 } 7 else 8 { 9 System.Windows.Controls.Button button = new System.Windows.Controls.Button(); 10 } 11 }產品以前有個功能,當需要用到一些沒有加載的程序集時,產品根據一些邏輯找到該程序集但是并不管該程序集是否運行的工程有關。但是現在改成了只會查找和加載和當前工程相關的程序集。也就是說對于WPF的工程來說,產品不會再去查找或者加載Silverlight的程序集。因此現在在WPF工程中執行AddButton方法時,會因找不到Silverlight程序集拋出“Could not load file or assembly 'System.Windows, Version=5.0.5.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e' or one of its dependencies”(注:此程序集不在GAC中,也不是Copy Local的)。找到了原因之后,我將AddButton的邏輯稍作改動如下:
1 public void AddButtonUsingSeperateMethod(bool isSiverlight) 2 { 3 if (isSiverlight) 4 { 5 this.AddSiverlightButton(); 6 } 7 else 8 { 9 this.AddWpfButton(); 10 } 11 } 12 13 private void AddSiverlightButton() 14 { 15 Silverlight.System.Windows.Controls.Button button = new Silverlight.System.Windows.Controls.Button(); 16 } 17 18 private void AddWpfButton() 19 { 20 System.Windows.Controls.Button button = new System.Windows.Controls.Button(); 21 }我將AddButton里的方法抽成了兩個獨立的方法,該用例便正常了。測試覺得很奇怪,問我為什么寫成兩個獨立的方法就可以,而獨立的方法便會有異常,邏輯明明是一樣的啊。我于是把CLR via C#找出來,找到“執行程序集代碼”的章節跟他解釋了一番,他便明白了其中的原因。
CLR第一次執行到某個方法時,JIT編譯器會將該方法的IL轉換成本地CPU指令(步驟參見下圖,來自CLR via C#)。因此當執行AddButton方法時,會將里面的IL代碼全部解釋為CPU指令,當轉換"Silverlight.System.Windows.Controls.Button button = new Silverlight.System.Windows.Controls.Button();"時,會需要加載定義該類的程序集查找該類的信息,由于找不到該程序集便有異常發生了。但是AddButtonUsingSeperateMethod就不一樣了,由于此時是WPF工程,JIT在轉換AddButtonUsingSeperateMethod時并不立即將AddSiverlightButton這個方法的具體實現也一并轉換成CPU指令,因而也就不需要加載Silverlight的程序集,從而避免了異常的發生。
?
拆箱
“拆箱的代價比裝箱低得多,拆箱其實就是獲取一個指針的過程,該指針指向包含在一個對象中的原始值類型(數據字段),拆箱不要求在內存中復制任何字段”?
下面的代碼將struct類型p裝箱成object并賦值給o,隨后又將o拆箱成Point并賦值給p。通常我們所指的拆箱便是(Point)o這個表達式,其實這個表達式包含了拆箱和賦值兩個操作。
1 public struct Point 2 { 3 public int X; 4 public int Y; 5 } 6 7 class Program 8 { 9 static void Main(string[] args) 10 { 11 Point p = new Point() { X = 1, Y = 1 }; 12 object o = p; 13 p = (Point)o; 14 } 15 }單純地就拆箱來講只是獲取一個指針,但隨后會緊接著一個賦值的動作。那么這個值是賦到哪里呢?我們來嘗試著將拆箱后的o中的X的值直接改成2,編譯的時候我們會得到一個“Cannot modify the result of an unboxing conversion”,從MSDN可以得知,這是CS0445的編譯錯誤,從該錯誤的MSDN解釋可得知,我們是將拆箱的值賦值到內存中的臨時變量中的。因此要記住,我們是不能直接修改拆箱結果的值的,必須先將其賦值程序中事先定義好的變量中。
1 ((Point)o).X = 2;由于個人能力所限,文中解釋不免有不足和錯誤之處,望各位讀者不吝指正,供大家共同學習進步,也便于以后分享更好的文章。
Source
轉載于:https://www.cnblogs.com/chainyy/archive/2013/01/12/2857147.html
總結
以上是生活随笔為你收集整理的CLR via C# 之管中窥豹(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 关于索爱MT15i连接win7——MTP
- 下一篇: C# 事务提交(非数据库)