CLR via C# 之管中窥豹(一)
記得剛畢業(yè)那會(huì),看過(guò)一陣CLR via C#,由于書(shū)中知識(shí)對(duì)于我來(lái)說(shuō)過(guò)于深?yuàn)W,最終只得放棄。而今重新拾起此書(shū)并結(jié)合工作中的一些經(jīng)驗(yàn),偶有小感就寫(xiě)成隨筆分享給大家,便于共同探討,也能幫助我成長(zhǎng)。
執(zhí)行程序集的代碼
前幾天組里有個(gè)測(cè)試找我?guī)退麄兛磦€(gè)自動(dòng)化測(cè)試的用例,該用例從某一天就一直拋出加載程序集失敗的異常。在這里我用一個(gè)場(chǎng)景去模擬當(dāng)時(shí)的情形 ,有這么一個(gè)測(cè)試用例:我們測(cè)試Visual Studio創(chuàng)建工程(隨機(jī)創(chuàng)建Silverlight或者WPF),并為新建的工程添加一個(gè)按鈕。我們需要為WPF和Silverlight創(chuàng)建相應(yīng)的按鈕,但是我們把這兩種按鈕添加的邏輯放到一個(gè)方法里面,并通過(guò)一個(gè)布爾值去區(qū)分不同的工程。添加按鈕邏輯的樣例代碼如下:
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 }產(chǎn)品以前有個(gè)功能,當(dāng)需要用到一些沒(méi)有加載的程序集時(shí),產(chǎn)品根據(jù)一些邏輯找到該程序集但是并不管該程序集是否運(yùn)行的工程有關(guān)。但是現(xiàn)在改成了只會(huì)查找和加載和當(dāng)前工程相關(guān)的程序集。也就是說(shuō)對(duì)于WPF的工程來(lái)說(shuō),產(chǎn)品不會(huì)再去查找或者加載Silverlight的程序集。因此現(xiàn)在在WPF工程中執(zhí)行AddButton方法時(shí),會(huì)因找不到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的邏輯稍作改動(dòng)如下:
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里的方法抽成了兩個(gè)獨(dú)立的方法,該用例便正常了。測(cè)試覺(jué)得很奇怪,問(wèn)我為什么寫(xiě)成兩個(gè)獨(dú)立的方法就可以,而獨(dú)立的方法便會(huì)有異常,邏輯明明是一樣的啊。我于是把CLR via C#找出來(lái),找到“執(zhí)行程序集代碼”的章節(jié)跟他解釋了一番,他便明白了其中的原因。
CLR第一次執(zhí)行到某個(gè)方法時(shí),JIT編譯器會(huì)將該方法的IL轉(zhuǎn)換成本地CPU指令(步驟參見(jiàn)下圖,來(lái)自CLR via C#)。因此當(dāng)執(zhí)行AddButton方法時(shí),會(huì)將里面的IL代碼全部解釋為CPU指令,當(dāng)轉(zhuǎn)換"Silverlight.System.Windows.Controls.Button button = new Silverlight.System.Windows.Controls.Button();"時(shí),會(huì)需要加載定義該類(lèi)的程序集查找該類(lèi)的信息,由于找不到該程序集便有異常發(fā)生了。但是AddButtonUsingSeperateMethod就不一樣了,由于此時(shí)是WPF工程,JIT在轉(zhuǎn)換AddButtonUsingSeperateMethod時(shí)并不立即將AddSiverlightButton這個(gè)方法的具體實(shí)現(xiàn)也一并轉(zhuǎn)換成CPU指令,因而也就不需要加載Silverlight的程序集,從而避免了異常的發(fā)生。
?
拆箱
“拆箱的代價(jià)比裝箱低得多,拆箱其實(shí)就是獲取一個(gè)指針的過(guò)程,該指針指向包含在一個(gè)對(duì)象中的原始值類(lèi)型(數(shù)據(jù)字段),拆箱不要求在內(nèi)存中復(fù)制任何字段”?
下面的代碼將struct類(lèi)型p裝箱成object并賦值給o,隨后又將o拆箱成Point并賦值給p。通常我們所指的拆箱便是(Point)o這個(gè)表達(dá)式,其實(shí)這個(gè)表達(dá)式包含了拆箱和賦值兩個(gè)操作。
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 }單純地就拆箱來(lái)講只是獲取一個(gè)指針,但隨后會(huì)緊接著一個(gè)賦值的動(dòng)作。那么這個(gè)值是賦到哪里呢?我們來(lái)嘗試著將拆箱后的o中的X的值直接改成2,編譯的時(shí)候我們會(huì)得到一個(gè)“Cannot modify the result of an unboxing conversion”,從MSDN可以得知,這是CS0445的編譯錯(cuò)誤,從該錯(cuò)誤的MSDN解釋可得知,我們是將拆箱的值賦值到內(nèi)存中的臨時(shí)變量中的。因此要記住,我們是不能直接修改拆箱結(jié)果的值的,必須先將其賦值程序中事先定義好的變量中。
1 ((Point)o).X = 2;由于個(gè)人能力所限,文中解釋不免有不足和錯(cuò)誤之處,望各位讀者不吝指正,供大家共同學(xué)習(xí)進(jìn)步,也便于以后分享更好的文章。
Source
轉(zhuǎn)載于:https://www.cnblogs.com/chainyy/archive/2013/01/12/2857147.html
總結(jié)
以上是生活随笔為你收集整理的CLR via C# 之管中窥豹(一)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 关于索爱MT15i连接win7——MTP
- 下一篇: C# 事务提交(非数据库)