我已經假定你安裝了宇宙第一IDE:visual studio 2017版本了,一個好的IDE會讓你在敲代碼的時候獲得一個好心情,想想多年以前,很多人還是用VC++6.0,估計在現在,還是有一部分的人在使用,那個IDE用起來非常的不順手,連提示錯誤都沒有,很多時候我們只是手賤打錯了個字,為了查錯那個辛苦啊。扯遠了,反正我沒用過VC++6.0,如果你開始使用,推薦也是從最新版開始吧。
我們開始新建第一個winform項目,點擊新建項目后就彈出來下面的對話框:
新建完成后,就是如下的界面了:
這時候點擊F5運行,然后就是這樣:
此處就出現了一個窗體,操作熟練的話,整個過程不到5秒就創建成功一個窗體了,一切都是那么的自然,自然的讓我們以為創建窗口就應該是這個樣子的,簡單,高效,不得不說,這也是微軟這么多年來努力的目標之一,就是讓大家在開發程序的時候,可以盡可能的快速,便捷式操作,傻瓜式操作,使得編程的門檻大幅度的降低,上述的操作交給一個完全的新手時,幾分鍾就教會了。然后教教他怎么顯示文本,怎么改變文本,估計也是幾分鍾的事情,就可以寫一個簡單的程序了。微軟這么做的結果就是降低編程門檻,越來越多的人來學習C#,但也導致了水平普遍偏低的結果,就比如創建這個窗口,你在創建一百個這樣的窗口,水平也沒有提升再多了,因為這簡單的幾部它就是沒什么技術含量的。
終於進入到了本文的重點了,講解我們用C#編寫的程序的運行機制,這部分的內容對於新人來講確實挺難理解的,我一開始學習的時候簡直就是看天書一樣的,所以我會盡量的將我所知道的用平實的語言講出來,這部分內容對於理解C#來說至關重要,也是進階的必經之路。所以我先大概說明一下運行機制,再分部完成。
就比如上面生成的exe程序,它到底是什么玩意,我想很多人都會疑問,剛學習C#的我也是這樣。
- 我們首先在VS中寫了很多的代碼,點擊生成或是調試的時候,IDE使用了C#編譯器將我們寫的所有的代碼編譯成了一種中間語言IL語言,寫入到了生成的exe中。
- 可以想想看exe包含了什么東西,我們在上述的項目中定義了新的類Form1,那么這些類系統又不提供,所以肯定會把類寫入到exe中,只要是自定義的類肯定會寫入進去。
- 我們可以猜測exe文件應該還有個文件頭,來標識這是一個可執行的Win32程序,我們在創建項目時可以選擇.NET版本,應該還包含了環境版本
到這里我們的猜測已經非常的接近事實的情況了, 所以當我們點擊exe程序的時候,windows到底干了什么東西。
首先windows會檢查exe文件的文件頭,檢查程序類型是不是PE32文件頭還是PE32+文件頭的,這個文件頭要求程序的運行環境,是不是32位,還是64位的,如果和操作系統不匹配,則不會運行,檢查.NET 的版本號。
windows檢查完exe后,檢查合格后,接下來就要創建程序需要運行的進程空間了,在進程的地址空間加載MSCorEE.dll(一個.NET framework自帶的鏈接庫,可以在安裝目錄找到)。
MSCorEE.dll的用處非常大,進程的主線程會調用組件的方法來初始化運行的CLR,然后加載exe的數據(就是中間語言IL代碼,包含了所有的類型說明和數據,即使加載了,還是IL代碼,還不不能直接運行的,如果你的exe還引用了其他的dll,那么所有的關聯的dll都會加載進來)。
然后MSCorEE.dll組件調用Main方法,這個和我們大學學的C語言是一致的,但是問題出現了,我們上面說過這時候CLR加載的還是IL代碼,IL代碼又不能直接運行,所以CLR內部的JITCompiler方法就出來干活了,工作是將IL代碼編譯成本機的CPU指令,這樣操作后Main方法才可以真正的運行,如果Main方法調用了其他方法(這不是廢話么),那么JITCompiler又出來工作了,如果每次調用方法,都要重新編譯一次,那么應用程序的性能就非常差了,所以CLR使用了緩存的機制,所有的方法只有在第一次調用的時候存在一點性能損耗,以后調用就直接使用了本地指令。
繞着這么多的彎路,終於窗體運行了,展示給你看了,汗顏-------
這里肯定會有小伙伴跳出來說,這么搞累不累啊,我也想說,確實挺累的,為了運行一個程序,繞了一個大彎,我還記得我在大學的時候學的單片機,雖然我使用C語言來寫程序的,但是編譯器直接編譯成了匯編寫入ROM中,然后指針就可以直接調用程序了,你看,多么的簡單明了。相比較而言,我們就不能用C#寫的程序生成windows直接可以運行的程序嗎?或者說直接生成IL的exe,再編譯一次直接生成機器語言多好,運行效率會高很多。
要想回答這個問題,我們需要探究一下IL語言為什么會產生,大致就能回答上述的問題了,說到IL的產生,又不得不說.NET的生成歷史,當年微軟看到JAVA發展如你中天時,心里也癢癢了,也想做一個新的語言,運行在虛擬機上,這樣的程序和平台無關,可以實現程序的方便移植,雖然后來做着做着還是綁定了windows系統,但是至少和windows版本沒有了太大的關系,比如上述的exe程序,是基於.NET 4.5的,只要安裝了.NET 4.5的話就可以很好的支持,不必為了針對哪個系統,哪個CPU架構來區別對待。事實上基於CLR的IL可以實現的功能非常的強大,擁有完整的面向對象的機制,提供了拋出異常和處理模型,只是在C#層面就只能實現部分的CLR功能,也就是說,如果CLR不支持的功能,在C#層面就肯定不支持了。
如果直接生成了基於機器指令的exe程序,事實上微軟完全可以做到,但是這也喪失了動態性能,JITCompiler在即時編譯指令時,會根據當前的cpu來優化本地指令,為特定cpu生成的程序有可能會在其他電腦無法運行,這就失去了程序的健壯性,誰都不會希望開發出這種程序吧。
關於性能損耗,微軟早就意識到這個問題了,花了非常大的人力物力來優化JIT的性能損耗,在我的經驗中,性能非常的高效,已經滿足絕大多數的場景。
到此處為此,其實已經說的非常完整了,需要多讀幾遍,才能比較好的理解,也可以自己去查查看IL代碼是什么樣子的,相信還有很大的收獲的。