1. 首頁
  2. 面試

.net面試題及詳解

.net面試題及詳解

1.什麼是CLR

公共語言執行時(Comman language Runtime),是一個可由多種程式語言使用的“執行時”。CLR的核心功能:程式集載入,異常處理,執行緒同步,記憶體管理等可由CLR

的所有語言使用.

2.什麼是IL

Intermediate language

中間語言,.net程式在經過編譯後就成為IL程式碼。執行時CLR將IL語言編譯成CPU能識別的CRU指令。IL也可以叫做託管程式碼,IL可以訪問CLR所提供的所有功能。

3.什麼是JIT,它是如何工作的?

即時編譯器,由CLR呼叫,負責將IL語言編譯成本地CPU指令。

工作原理:

當程式被第一次呼叫的時候,CLR會指向包含在CLR內部定義的特殊函式,這個函式就是JITCompiler。JITComliler負責將IL程式碼編譯成本地指令。

JITCompiler知道實際呼叫了哪個方法,以及該方法是哪些型別定義的。JITCompiler會在定義該型別的程式集的元資料中查詢該方法的IL程式碼。

並將IL編譯成本地CPU指令。編譯好的結果被放在一個記憶體塊中,JITCompiler返回CLR為型別定義的內部資料結構。找到被呼叫方法對應的那條記錄,

並修改最初對於JITCompiler的引用。讓其指向記憶體塊中被呼叫方法剛剛編譯好的CPU指令地址,最後執行被呼叫方法的CPU指令。

4.GC是什麼,簡述一下GC的工作方式?

垃圾回收(garbage collection)

Dot Net的垃圾回收可以分為兩個步驟,第一步進行“標記”,垃圾回收器假設所有的物件都是垃圾,然後開始遍歷每一個“根”(根包含指向引用型別物件的一個指標,值型別物件永遠不會被認為是一個根),如果發現一個根引用了一個物件(非NULL),就對物件進行標記。沒有被標記的物件被認為是垃圾。第二個階段就是“壓縮”,其實就是將後面的物件移動到已經成為垃圾的物件位置,使得原來的託管堆更為緊湊。從而釋放了託管堆。

GC類中的方法影響何時對物件進行垃圾回收以及何時釋放物件所分配的資源。此類中的屬性提供以下資訊:系統可用記憶體總量、分配給物件的記憶體的週期類別(代)。

GC跟蹤並回收託管記憶體中分配的物件。垃圾回收器定期執行垃圾回收以回收分配給沒有有效引用的物件的記憶體。當使用可用記憶體不能滿足記憶體請求時,垃圾回收會自動進行。或者,應用程式可以使用 Collect 方法強制進行垃圾回收。

垃圾回收由以下步驟組成:

GC搜尋託管程式碼中引用的託管物件。

GC嘗試完成沒有被引用的物件。

GC釋放沒有被引用的物件並回收它們的記憶體。

在回收期間,如果GC在託管程式碼中找到對某物件的一個或多個引用,則不會釋放該物件。然而,GC不識別非託管程式碼中對物件的引用,因此,除非明確禁止,否則它有可能釋放非託管程式碼中以獨佔方式使用的物件。KeepAlive 方法提供一種機制,該機制可防止垃圾回收器回收在非託管程式碼中仍使用的物件。

5.在.NET程式執行過程中,什麼是堆,什麼是棧?什麼情況下會在堆(棧)上分配資料?它們有效能上的區別嗎?“結構”物件可能分配在堆上嗎?什麼情況下會發生,有什麼需要注意的?

.NET程序被建立時就會有一個堆隨之被建立, 用來儲存該程序在執行中需要使用的物件/資料; 當一個執行緒被建立時, 會有一個棧被建立,用來儲存方法呼叫引數, 區域性變數等輕量型資料.

當一個類裡面包含一個結構體型別的變數時, 該結構體型別會被分配在堆上.

>泛型的作用是什麼?它有什麼優勢?它對效能有影響嗎?它在執行時的行為是什麼?.NET BCL中有哪些泛型型別?舉例說明平時程式設計中您定義的泛型型別

泛型的作用是什麼?

泛型的作用在於“演算法的重用”。(這點其實很好理解,原來的ArrayList只能接受Object,現在透過List可以接受任何型別,也就是說ArrayList的方法都被各個型別重用了。但是Dot Net的泛型有個比較制肘地方,就是你很難對數值型別(值型別)進行演算法抽象,因為這牽涉到運算子過載的問題,同時Dot Net的泛型的型別引數也不能約束成一個基元值型別(如int、double、float) 。)

它有什麼優勢?

第一:原始碼保護。(如果你知道C++模板對泛型的實現機制,就會知道C++在編譯的時候根據對泛型的呼叫,自動“內聯”了一個實現,這樣泛型的內容就暴露了,爾DotNet的實現方式就不同了,泛型類和方法會被編譯成IL,在執行的時候由JIT負責將IL變化為指定型別引數的原生代碼,從而保護了原始碼)

第二:型別安全。(這點是最顯而易見的,拋棄了使用ArrayList時各種醜陋的強制型別轉換)

第三:更清晰地程式碼。因為沒有了強制型別轉換,所以程式碼自然顯得更清晰,但是使用泛型時候帶來的<>有時候確實也會讓人搞糊塗,幸好泛型方法可以用型別推斷或者using語句來進一步簡化寫法。

第四:更好的效能,因為值型別可以避免裝箱和拆箱所帶來的損耗(垃圾回收的次數也會減少)。(這點正是泛型神奇的地方,開發歷史上抽象能力的上升往往意味著效能的下降,但是泛型卻不是!泛型抽象了演算法,但是C++和DotNet對泛型的實現能夠讓效能無損,並且更快。Java的擦除法泛型就沒有這種效能上的好處。)

它對效能有影響嗎?

對效能有積極的影響,因為值型別可以避免裝箱和拆箱所帶來的負面影響,避免了垃圾回收,使得效能顯著提高。但是對引用型別這種影響就不明顯了。但是需要注意的是首次為一個特定資料型別呼叫方法時,CLR都會為這個方法生成原生代碼。這會增大應用程式的工作集大小,從而影響效能。

它在執行時的行為是什麼?

使用泛型型別引數的一個方法在進行JIT編譯時,CLR獲取IL,用指定的型別實參進行替換,然後建立原生代碼。需要特別注意的是引用型別是共享程式碼的,而對值型別就會為每一種生成獨立的一份型別程式碼。但是需要指出的是引用型別的這種程式碼共享並不會造成封閉型別只執行一次建構函式(就算是靜態建構函式也是這樣的)。

.NET BCL中有哪些泛型型別?

List、Dictionary、Queue、Stack、SortedList和SortedDictionary、LinkedList等等。

舉例說明平時程式設計中您定義的泛型型別。

泛型的出現會替換原來一部分使用多型的地方從而提高效能和帶來更好的編譯時檢查,這樣就不需要在子類和超類(介面)間頻繁轉換了。比如你要根據情況打出各種報表,那麼先把報表類定義成泛型類從而可以共享報表一系列的演算法。

> 異常的作用是什麼?.NET BCL中有哪些常見的異常?在程式碼中您是如何捕獲/處理異常的?在“catch (ex)”中,“throw”和“throw ex”有什麼區別?您會如何設計異常的結構,什麼情況下您會丟擲異常?

異常的作用是什麼?

異常用於處理系統級或者應用程式級的錯誤狀態。這就會引發另外幾個問題,異常相比原來使用的返回錯誤程式碼的優點在哪裡?異常處理是一種結構化的處理過程,個人認為他最大的優點就在於將“成功場景”剝離出來,使得程式碼更加清晰自然。但是異常處理相對於返回錯誤碼有一個缺點,那就是他會失去發生異常的位置。不過異常本身提供了很多幫助除錯問題的工具,一般都帶有棧跟蹤,這樣位置的問題就得到一定程度的解決。還有就是IF和異常之間的選擇,我記得以前有人討論過在各種分支下是使用異常來處理各種“失敗場景”的分支還是使用IF或者SWITCH來處理呢?這其實是一個假問題,因為異常和錯誤是有概念上的不同的,這裡的錯誤是指有違“主成功場景”的“異常場景”,爾異常是指當程式不能完成其名字所表示功能時的錯誤。所以需要強調不要使用異常來區分各種失敗場景,異常壓根就不是用來幹這件事情的!

.NET BCL中有哪些常見的異常?

隨便說幾個,最著名的恐怕就是那句像繞口令一樣的'“未將物件引用設定到物件例項”了,還有那些基本一出現整個應用程式就被判死刑的“堆疊溢位”、“記憶體無法分配”異常了。

在程式碼中您是如何捕獲/處理異常的?

這道題的回答可以體現你是什麼“級別”的程式設計師,這個級別倒不是說水平的高低,是指經常寫哪一類的程式,如果對異常的捕獲比較“激進”(經常捕獲異常)那麼這個人應該是一個應用級的程式設計師。如果對捕獲異常比較謹慎那麼應該是框架級別的程式設計師,這些人經常寫給別人使用的程式碼,如果無故的使用異常處理來越俎代庖,那後果很嚴重了,這裡說一個我經歷的事,剛畢業的時候我和同事做一個WEB的專案,專案裡用第三方的Grid,那個Grid在發生異常的時候會自己報一個錯誤,你知道我們有多傻眼了吧,我們需要的是我們來抓住異常,然後報出一句對使用者友好的錯誤,但是那個控制元件卻幹了這麼個蠢事。

我覺得普通程式設計師用的最多的CATCH就是抓住資料的異常,然後回滾資料庫來事務處理。這是一個典型的場景,因為你明確並且能夠很好的恢復狀態。

在“catch (ex)”中,“throw”和“throw ex”有什麼區別?

throw 重新丟擲異常但是不破壞異常發生的呼叫棧爾“throw ex”會重置呼叫棧這樣捕獲異常的人會以為程式碼出錯在這裡。

您會如何設計異常的結構,什麼情況下您會丟擲異常?

首先我會盡量的使用系統定義的那些異常,如果我需要處理某一特定類別的異常,而且處理方式和通常處理方式不同那麼就考慮自定義異常,還有如果需要呼叫方用一種統一的方式來處理異常那麼自定義異常就是一個好的選擇。結構的話當然基類是Sysytem.Exception,儘量使用扁平化異常的層次。可以考慮用泛型類來定義異常。

我寫的程式碼不能完成名字所說明的功能,那麼我就會丟擲異常。

> List和T[]的區別是什麼,平時你如何進行選擇?Dictionary是做什麼的?.NET BCL中還有哪些常用的容器?它們分別是如何實現的(哪種資料結構)?分別是適用於哪些場景?

List和T[]的區別明顯有本質的區別,List 是動態分配記憶體的連結串列,