net高級程序員面試題-c#基礎

c#基礎:
一、請介紹關鍵字internal、sealed、readonly、static、is、as、params、this。請結合實際場景說明你在項目中的使用狀況。
(1)    internal 訪問修飾符 只有在同一程序集的文件中,內部類型或成員纔是可訪問的,內部訪問一般用於基於組件的開發,由於它使一組組件可以以私有方式進行合做,而沒必要嚮應用程序代碼的其他部分公開。
(2)   sealed 修飾符能夠應用於類、實例方法和屬性。密封類不能被繼承。密封方法會重寫基類中的方法,但其自己不能在任何派生類中進一步重寫。當應用於方法或屬性時,sealed 修飾符必須始終與 override一塊兒使用
(3)   readonly 字段能夠在聲明或構造函數中初始化。所以,根據所使用的構造函數,readonly 字段可能具備不一樣的值。const 字段是編譯時常數,常數表達式是在編譯時被徹底計算出來,它只能在該字段的聲明中初始化. const 默認就是靜態的,而 readonly 若是設置成靜態的就必須顯示聲明。
(4)  static 修飾符聲明屬於類型自己而不是屬於特定對象的靜態成員,儘管類的實例包含該類全部實例字段的單獨副本,但每一個靜態字段只有一個副本。不可使用  this 來引用靜態方法或屬性訪問器。若是對類應用 static 關鍵字,則該類的全部成員都必須是靜態的。
(5)  abstract 修飾符指示所修飾的內容缺乏實現或未徹底實現。 abstract 修飾符可用於類、方法、屬性、索引器和事件。 標記該類爲抽象類,抽象方法只能由派生類實現,是一個隱式的虛方法。
(6)  is 檢查對象是否與給定類型兼容。 例如,if (obj is MyObject) 的代碼能夠肯定對象是否爲 MyObject 類型的一個實例,或者對象是否爲從 MyObject 派生的一個類型。請注意,is 運算符只考慮引用轉換、裝箱轉換和取消裝箱轉換。 不考慮其餘轉換,如用戶定義的轉換。在 is 運算符的左側不容許使用匿名方法。 lambda 表達式屬於例外
(7)  as用於在兼容的引用類型之間執行轉換,as 運算符相似於強制轉換操做;可是,若是轉換不可行,as 會返回 null 而不是引起異常。更嚴格地說,這種形式的表達式 就至關於 obj as type===>obj is type ? (type)obj : (type)null
as 運算符只執行引用轉換和裝箱轉換。as 運算符沒法執行其餘轉換,如用戶定義的轉換,這類轉換應使用 cast 表達式來執行。
(8)   this 關鍵字引用類的當前實例(對象),還可用做擴展方法的第一個參數的修飾符。因爲靜態成員函數存在於類一級,而且不是對象的一部分,所以沒有 this 指針。 在靜態方法中引用 this 是錯誤的。
this能夠限定被類似的名稱隱藏的成員,例如當前實例有變量name,有一個方法的參數也是name,那麼此時this.name就是指當前實例的成員,而不是隻參數,起到一個區分的做用。This也能夠將對象做爲參數傳遞到其餘方法
(9)   params 關鍵字能夠指定在參數數目可變處採用參數的方法參數。在方法聲明中的 params 關鍵字以後不容許任何其餘參數,而且在方法聲明中只容許一個 params 關鍵字。public static void UseParams2(params object[] list){}
2 ref 和out
關鍵字使參數按引用傳遞(參數默認是按照值傳遞的)。其效果是,當控制權傳遞迴調用方法時,在方法中對參數所作的任何更改都將反映在該變量中。若要使用 ref或out參數,則方法定義和調用方法都必須顯式使用 ref 和out關鍵字。傳遞到 ref 參數的參數必須最早初始化。這與 out 不一樣,out 的參數在傳遞以前不須要顯式初始化
3 delegate委託 ,事件
是一種可用於封裝命名或匿名方法的引用類型,經過將委託與命名方法或匿名方法關聯,能夠實例化委託。 必須使用具備兼容返回類型和輸入參數的方法或 lambda 表達式實例化委託
 delegate void testDelegateMes 聲明瞭一個委託 能夠理解爲一個特殊的類
             testDelegateMes tdm1=new testDelegateMes(showMes);
           testDelegateMes tdm1 //能夠理解爲聲明瞭該類的一個變量
           new testDelegateMes(showMes);//將委託與命名方法或匿名方法關聯,此時tdm1就等價於showmes方法,一個委託能夠搭載多個方法
  委託是一個類,它定義了方法的類型,使得能夠將方法看成另外一個方法的參數來進行傳遞,這種將方法動態地賦給參數的作法,能夠避免在程序中大量使用If-Else(Switch)語句,同時使得程序具備更好的可擴展性。全部委託都有一個構造器默認獲取兩個參數,一個是對象引用@object,一個是引用了回調方法的整數method;在構造器內部這兩個參數被保存在_target和_methodPtr私有字段中,編譯器在定義委託類的時候定義了一個Invoke方法,在Invoke被調用時(默認使用委託時,實際上是調用了該委託的Invoke方法),它使用私有字段_target和_methodPtr在指定對象上調用包裝好的回調方法(委託代替方法執行的原理)。(invoke方法的簽名和委託的簽名匹配)
委託的屬性表現形式就是事件,利用委託的多播特性能夠將多個行爲與委託綁定。
4 請說一下靜態構造函數和默認構造函數的區別
               靜態構造函數同其餘靜態成員同樣是屬於類的,它用來初始化一些靜態成員。靜態構造函數只會被執行一次。也就是在建立第一個實例或引用任何靜態成員以前,由.NET自動調用。也就是說咱們沒法直接調用靜態構造函數。若是沒有寫靜態構造函數,而類中包含帶有初始值設定的靜態成員,那麼編譯器會自動生成默認的靜態構造函數。一個類只能有一個靜態構造函數。
5 請說一下屬性和字段的區別。
       屬性有比字段更大的靈活性和可擴展性,字段」是直接在類或結構中聲明的任何類型的變量。屬性提供靈活的機制來讀取、編寫或計算某個私有字段的值。 能夠像使用公共數據成員同樣使用屬性,但實際上它們是稱做「訪問器」的特殊方法。有助於提升方法的安全性和靈活性。對於屬性,你能夠自定義取值賦值的操做。能夠只讀也能夠只寫,而字段始終是可讀可寫的(字段通常屬於類私有的,在外部訪問他破壞了類的封裝型)
6 什麼是堆,棧, 值類型, 引用類型 ,裝修, 拆箱
託管堆和線程棧是內存上的兩塊存儲區域,應用程序的每一個線程都會被分配1m的存儲空間做爲線程棧,用於存儲自身的數據(局部變量,實參等)這塊內存區域的分配和回收不受應用程序干擾,當一個變量離開其做用域的時候內存空間當即被釋放。棧在內存中是由高內存地址往低內存地址填充,釋放是由低往高釋放(先進後出保證了不與變量的聲明週期起衝突)。棧中存儲值類型
另外一塊內存區域稱爲「堆(heap)」,在.NET 這種託管環境下,堆由CLR 進行管理,因此又稱爲「託管堆(managed heap)」。  託管堆存儲引用類型,類是引用類型,用new關鍵詞建立的對象分配的內存空間位於託管堆上。當對象使用完被垃圾回收機制回收時,空間會被回收   與棧不一樣,堆是從下往上分配,因此自由的空間都在已用空間的上面
通用類型系統(CTS)區分兩種基本類型:值類型和引用類型。它們之間的根本區別在於它們在內存中的存儲方式。值類型存儲於棧中,引用類型存儲在堆中。值類型比引用類型輕。緣由是它不做爲對象在託管堆中分配,不被垃圾回收,也不經過指針進引用。沒有堆上每一個對象成員都有的額外成員:(類型對象指針和同步塊索引),當這個值類型離開做用域時,所佔空間即被釋放
string是特殊的引用類型,字符串表明一個固定不變的Unicode字符序列(相似於不變集合同樣,每當改變都不是針對原來的對象的改變,而是產生的一個新的對象)。這種不變性意味着,一旦在堆中分配了一個字符串,它的值將永遠不會改變。若是值改變了,.NET就建立一個全新的String對象,並把它賦值給該變量。
裝箱:
值類型轉化爲引用類型要使用裝箱機制,裝箱分三步:
  1.  在託管堆中分配內存,分配的內存量是值類型各字段所需的內存量,還要加上託管堆上全部對象都有的兩個成員(類型對象指針和同步塊索引)
  2. 值類型的字段複製到新分配的堆內存
  3. 返回對象地址,如今該地址是對象引用。值類型成了引用類型。
拆箱:
將一個引用類型轉化爲值類型的時候,要拆箱。值類型轉爲引用類型分2步:
  1.  獲取已裝箱的對象(此時爲引用類型)的各個成員的地址;叫拆箱
  2.  將字段包含的值從堆中複製到基於棧的值類型實例中
拆箱不是將裝箱過程倒過來,拆箱的代價要比裝箱低不少,拆箱就是獲取指針的過程,該指針指向一個對象中的原始值類型(數據字段).緊接着拆箱每每會發生一次字段複製
發生裝箱和拆箱的幾種狀況:
1 發生值類型轉爲引用類型的狀況 會裝箱
2 類型在調用tostring方法時,內部並未重寫該虛方法,而是使用的基類(object)得tostring方法,會裝箱,在重寫了基類tostring方法的時候,是用base.tostring同樣會發生裝箱
3 是用gettype 同上,在值類型的派生類未重寫基類(object)得方法時同樣會發生裝箱
4 將值類型的某個實例轉換爲類型的某個接口時,要對實例進行裝箱。這是由於接口變量必須包含對堆對象的引用
7 CLR垃圾回收機制
clr要求全部對象都從託管堆分配,當使用new操做符建立一個對象的時候會在堆上分配一塊空間,並返回指向這塊存儲區域的指針(引用地址),當託管堆沒有足夠的空間的時候會執行垃圾回收。在執行垃圾回收時,
1 clr會暫停全部線程,
2 並標記全部對象是不是可達的(是否還有根(變量)引用它),不可達對象將被執行回收
3 以後進入壓縮階段,將全部可達的對象執行壓縮,使他們佔用連續的堆內存空間(好處是:1全部對象內存中緊挨在一塊兒,恢復了引用的局部化,減少了應用程序的工做集,提高了性能。2可用空間是連續的,容許其餘對象入住。3壓縮意味着解決了原生堆空間碎片化問題)。同時,clr還要從每一個根減去所引用的對象在內存中偏移的字節數,這樣就能保證每一個根仍是引用和以前同樣的對象。
4 clr恢復應用程序全部線程
簡單來講整個過程分五步:暫停進程的全部線程——>將全部對象的同步塊索引位設置爲0——>檢查全部根引用的對象,並標記其同步塊索引位1,沒有被根引用的對象保持原來的0不被從新標記——>刪除標記爲0的對象,執行壓縮,並根據對象在內存中偏移的字節數調整根的引用地址——>clr恢復暫停的線程
clr的GC是基於代的垃圾回收器
clr的代一共分爲3代:0,1,2;爲每一代都分配了預算容量(KB),這個預算容量是根據回收的狀況進行動態調整的,若是一次對第0代垃圾回收的對象較少,說明可用對象較多,則會增大對第一代預算,相反則相應減小容量預算。
對象被建立時未第0代對象,當0代存儲空間滿後,執行一次gc後倖存的對象升級爲第1代對象,以後在0代空間執行第2次gc後倖存的對象繼續升級爲第一代對象,直到第1代存儲空間也滿了,在執行gc時,會同時回收第0代和第一代的對象(此時1代空間的對象極可能已經有不可達對象等待被回收),這時原來存儲在第1代空間的倖存對象會被提高未第2代。第0代倖存的提高爲第1代。當全部存儲空間都滿了的時候,就內存溢出了。
垃圾回收的觸發條件:
  1. clr在檢測第0代超過預算時
  2. 代碼顯示調用system.GC的靜態方法Collect,強制垃圾回收
  3. window報告低內存時
  4. clr正在卸載AppDomain時,clr認爲一切都不是根,執行涵蓋全部代碼的垃圾回收
  5. 進程結束時,clr正常關閉,windows將回收進程的全部內存
 
8 深拷貝和淺拷貝
深拷貝和淺拷貝之間的區別在因而否複製了子對象。淺拷貝(影子克隆/shallow copy):只複製對象的值類型字段,對象的引用類型,仍屬於原來的引用. 深拷貝(深度克隆):不只複製對象的值類型字段,同時也複製原對象中的對象.就是說徹底是新對象產生的。例如一個學校類裏不只包含了schoolname屬性,還包含了students對象的引用,此時淺拷貝就是會建立schoolname的副本和對students對象指針的副本(並不會建立一個全新的students對象),而深拷貝則會建立一個全新的students對象副本出來
9 請說明Equals和==的區別。
       C#中的相等有兩種類型:引用相等(ReferenceEquals)和值相等(Equals)。值相等就是說兩個對象包含相同的值。而引用相等則比較的是兩個對象的引用是不是同一個對象。也就是說,若是ReferenceEquals爲True,則Equals必然爲True,反過來就不必定了 
       ==運算符(引用相等):經過過判斷兩個引用是否指示同一對象來測試是否相等。
      Equals是要實現值相等比較的,爲object類的方法,一個類默認狀況下,在不重寫基類Equals方法的時候對比的是對象的引用是否指向同一塊內存地址。重寫Equals函數的目的是爲了比較兩個對象的value值是否相同,例如利用equals比較八大包裝對象(如int,float等)和String類(由於該類已重寫了equals和hashcode方法)對象時,默認比較的是值,在比較其它自定義對象時都是比較的引用地址(例如自定義的類,由於沒有重寫equals方法)。
如何重寫equals方法:
主要用於經過對比自定義類中的每一個成員來對比兩個類是否值相等;重寫equals也要重寫hashcode方法
在建立1個對象的時候會自動爲這個對象建立hashcode,這樣若是咱們對2個對象重寫了euqals,意思是隻要對象的成員變量值都相等那麼euqals就等於true,此時在未重寫hashcode方法的時候,這兩個對象卻擁有不一樣的hashcode,由此將產生了理解的不一致,在存儲散列集合時(如Set類),將會存儲了兩個值同樣的對象,致使混淆,所以,就也須要重寫hashcode()
hashcode是用於散列數據的快速存取,如利用HashSet/HashMap/Hashtable類來存儲數據時,都是根據存儲對象的hashcode值來進行判斷是否相同的,在這裏對比兩個對象相同時,其中最早對比的是對象的hashcode,若是兩個對象的hashcode不一樣,則這兩個對象必然不一樣,從而大大提升了效率
10 面向對象三大特徵:
封裝:封裝就是將數據或函數等集合在一個個的類中,被封裝的對象一般被稱爲抽象數據類型。封裝的意義在於保護或者防止代碼(數據)被咱們無心中破壞。例如咱們會將屬於類自己的行爲,字段或方法定義爲private,外部不能能訪問它。使用屬性來控制對數據字段的修改或只讀只寫。訪問修飾符:Private,Protected(類和派生類能夠存取),Internal(只有同一個項目中的類能夠存取),Public
繼承:繼承主要實現代碼間的縱向聯繫,繼承了父類的子類也會有父類的行爲。
1、C#中的繼承符合下列規則:
    1. 繼承是可傳遞的。若是C從B中派生,B又從A中派生,那麼C不只繼承了B中聲明的成員,一樣也繼承了A中的成員。Object類做爲全部類的基類。
    2. 派生類應當是對基類的擴展。派生類能夠添加新的成員,但不能除去已經繼承的成員的定義。
    3. 構造函數和析構函數不能被繼承。除此以外的其它成員,不論對它們定義了怎樣的訪問方式,都能被繼承。基類中成員的訪問方式只能決定派生類可否訪問它們。
    4. 派生類若是定義了與繼承而來的成員同名的新成員,就能夠覆蓋已繼承的成員。但這並不由於這派生類刪除了這些成員,只是不能再訪問這些成員。
    5. 類能夠定義虛文法、虛屬性以及虛索引指示器,它的派生類可以重載這些成員,從而實現類能夠展現出多態性。
  2、new關鍵字
   若是父類中聲明瞭一個沒有friend修飾的protected或public方法,子類中也聲明瞭同名的方法。則用new能夠隱藏父類中的方法。(不建議使用)
  3、base關鍵字 base 關鍵字用於從派生類中訪問基類的成員:
    1. 調用基類上已被其餘方法重寫的方法。
    2. 指定建立派生類實例時應調用的基類構造函數。
多態:(重載就是多態)
編譯時的多態性:
  編譯時的多態性是經過重載來實現的。對於非虛的成員來講,系統在編譯時,根據傳遞的參數、返回的類型等信息決定實現何種操做。
  運行時的多態性:運行時的多態性就是指直到系統運行時,才根據實際狀況決定實現何種操做。C#中,運行時的多態性經過虛成員實現。編譯時的多態性爲咱們提供了運行速度快的特色,而運行時的多態性則帶來了高度靈活和抽象的特色。
   2、實現多態:接口多態性。繼承多態性。經過抽象類實現的多態性。
  3、override關鍵字:重寫父類中的virtual修飾的方法,實現多態。
 
11 請談一下你對Exception的理解
在 C# 中,程序中的運行時錯誤經過使用一種稱爲「異常」的機制在程序中傳播。異常由遇到錯誤的代碼引起,由可以更正錯誤的代碼(try catch)捕捉。 一旦引起了一個異常,clr自上而下搜索匹配的catch塊,一個try塊對應多個catch塊,越具體的catch應該在上面,接着是她們的基類型,最後是exception類,未指定也是exception類型。若是上下順序反了,那麼具體的catch塊會執行不到,編譯器會報錯。try catch 之後,若是隻是處理了捕獲的異常(例如記日誌),沒有拋出異常(throw),後續代碼會繼續執行
throw是拋出一個異常,中斷執行後續代碼,若是一個方法可能會有異常,但你不想處理這個異常,就是用throw,誰調用了這個方法誰就要處理這個異常,或者繼續拋出。
throw和throw ex
1 throw ex 拋出與catch捕捉到的相同的異常對象,致使clr重置該異常的起點。認爲你catch到的異常已經被處理了,只不過處理過程當中又拋出新的異常,從而找不到真正的錯誤源 try{ }catch (Exception ex){ throw ex; }
2 throw 從新拋出異常對象,clr不會重置起點(推薦使用這個)try{} catch{ throw;}
3 或者對異常就行從新包裝,保留原始異常點信息,而後拋出
finally:
不管代碼有沒有拋出異常,finally塊始終會執行。應該先用finally塊清理那些已經成功的操做,還能夠用finally顯示釋放對象避免資源泄露。Finally 塊使程序員可以清除停止的 try 塊可能遺留下的任何模糊狀態,或者釋聽任何外部資源(例如圖形句柄、數據庫鏈接或文件流),而無需等待運行時中的垃圾回收器終結這些對象.
使用了 lock,using,foreach的語句,c#編譯器會自動加上try finally塊,並在finally中自動釋放資源
 
能夠在一個線程中補獲異常,在另一個線程中從新拋出異常;
clr在調用棧中向上查找與拋出的異常對象類型匹配的catch塊,沒有任何catch塊匹配拋出的異常類型,就會發生一個未處理的異常
 
十二、你平時經常使用的集合類有哪些? 分別有什麼區別?請結合實際場景說明你在項目中的使用狀況。
               System.Collections命名空間包含各類集合對象和接口的定義(如列表、隊列、位數組、哈希表和字典)System.Collections.Generic 命名空間包含定義泛型集合的接口和類,泛型集合容許用戶建立強類型集合,它能提供比非泛型強類型集合更好的類型安全性和性能。
數組、arraylist、list、hashtable、directonary、stack堆棧、quene隊列
數組:數組是固定大小的,不能伸縮,數組要聲明元素的類型
a ArrayList動態數組能夠存儲任何類型,不像List泛型那樣有嚴格要求,ArrayList就至關因而list<object>,List類在大多數狀況下執行得更好而且是類型安全的。注意list非線程安全的,多線程中操做一個list最好使用ConcurrentList,和ConcurrentDictionary同樣內部自帶加速機制
b HashTable應用場合:作對象緩存,樹遞歸算法的替代,和各類需提高效率的場合。HashTable中的key/value均爲object類型,由包含集合元素的存儲桶組成。HashTable的優勢就在於其索引的方式,速度很是快。若是以任意類型鍵值訪問其中元素會快於其餘集合,特別是當數據量特別大的時候,效率差異尤爲大。
c Hashtable和Dictionary<K, V>類型  
1:單線程中推薦使用Dictionary,有泛型優點,且讀取速度較快,容量利用更充分.  
2:多線程中推薦使用Hashtable,默認Hashtable容許單線程寫入, 多線程讀取對Hashtable進一步調用Synchronized()方法能夠得到徹底線程安全的類型,而Dictionary非線程安全,必須人爲使用lock語句進行保護, 效率大減。  .net提供了另一個字典類ConcurrentDictionary,是線程安全的支持併發操做
3:Dictionary有按插入順序排列數據的特性(注:但當調用Remove()刪除過節點後順序被打亂), 所以在須要體現順序的情境中使用Dictionary能得到必定方便。
d HashTable、HashMap、HashSet之間的區別
HashTable是基於Dictionary的key value集合,是線程安全的
HashMap是基於Map接口的一個實現,HashMap能夠將空值做爲一個表的條目的key或者value,HashMap中因爲鍵不能重複,所以只有一條記錄的Key能夠是空值,而value能夠有多個爲空,但HashTable不容許null值(鍵與值均不行)
HashSet 是set的一個實現類,存儲的是一個對象列表,底層採用的是HashMap進行實現的,可是沒有key-value,只有HashMap的key set的視圖,HashSet不允許重複的對象
 
1三、什麼是接口,什麼是抽象類?兩者有什麼區別?請結合實際場景說明你在項目中的使用狀況。
抽象類和接口都是對業務的一種抽象方式。
一、接口定義了一種行爲,一種規則,它告訴了你要作什麼,但不會去具體實現。當一個類繼承了這個接口的時候,它將負責實現這個接口
 二、當類選擇實現某個接口的時候,類必須將這個接口所有實現,不能只實現其中一部分。
 三、接口和抽象類的區別:一個類只能繼承一個父類,但一個類能夠同時實現多個接口,格式爲: 類名:接口1,接口2
 四、接口裏的成員方法(行爲),沒有修飾符,但接口自己是能夠有修飾符的   
 五、抽象類的做用:負責定義「實現和部分的動做」(抽象類中能夠實現某些方法),接口只負責定義動做不負責實現
interface的應用場合:
  1. 類與類以前須要特定的接口進行協調,而不在意其如何實現。
  2. 做爲可以實現特定功能的標識存在,也能夠是什麼接口方法都沒有的純粹標識。
  3. 須要將一組類視爲單一的類,而調用者只經過接口來與這組類發生聯繫。
  4. 須要實現特定的多項功能,而這些功能之間可能徹底沒有任何聯繫。
abstract class的應用場合:一句話,在既須要統一的接口,又須要實例變量或缺省的方法的狀況下,就可使用它。最多見的有:
  1. 定義了一組接口,但又不想強迫每一個實現類都必須實現全部的接口。能夠用abstract class定義一組方法體,甚至能夠是空方法體,而後由子類選擇本身所感興趣的方法來覆蓋。
  2. 某些場合下,只靠純粹的接口不能知足類與類之間的協調,還必需類中表示狀態的變量來區別不一樣的關係。abstract的中介做用能夠很好地知足這一點。
  3. 規範了一組相互協調的方法,其中一些方法是共同的,與狀態無關的,能夠共享的,無需子類分別實現;而另外一些方法卻須要各個子類根據本身特定的狀態來實現特定的功能
 典型的是包含主訂單和子訂單的系統中應該使用抽象類,由於他們有共享的業務邏輯不須要子訂單類實現,同時也有各子訂單必須實現訂單的操做約定
1四、什麼是進程,什麼是線程,什麼是AppDomain?三者有什麼區別?請結合實際場景說明你在項目中的使用狀況。
答:進程是系統進行資源分配和調度的單位;線程是CPU調度和分派的單位,一個進程能夠有多個線程,這些線程共享這個進程的資源。
               AppDomain表示應用程序域,它是一個應用程序在其中執行的獨立環境。是CLR的運行單元,它能夠加載Assembly、建立對象以及執行程序。AppDomain是CLR實現代碼隔離的基本機制。AppDomain被建立在進程中,一個進程內能夠有多個AppDomain。一個AppDomain只能屬於一個進程。AppDomain是個靜態概念,只是限定了對象的邊界;線程是個動態概念,它能夠運行在不一樣的AppDomain。一個AppDomain內能夠建立多個線程,可是不能限定這些線程只能在本AppDomain內執行代碼。每一個appdomain都有一個託管堆,每一個託管堆內有兩塊區域,一塊存儲對象,一塊存儲對象元數據(靜態成員)。
1五、請談一下你對泛型的理解。請結合實際場景說明你在項目中的使用狀況。
  一、所謂泛型,即經過參數化類型來實如今同一份代碼上操做多種數據類型,泛型編程是一種編程範式,它利用「參數化類型」將類型抽象化,從而實現更靈活的複用。 C#泛型賦予了代碼更強的類型安全,更好的服用,更高的效率,更清晰的約束。
泛型的意義何在?類型安全和減小裝箱、拆箱並非泛型的意義,而是泛型帶來的兩個好處而已(或許在.net泛型中,這就是明顯的好處) 泛型的意義在於—把類型做爲參數,它實現了代碼見的很好的橫向聯繫,咱們知道繼承爲了代碼提供了一種從上往下的縱向聯繫, 但泛型提供了方便的橫向聯繫(從某種程度上說,它和AOP在思想上有相同之處)
二、泛型類型參數:在【泛型類型】或【方法定義】中,類型參數是客戶端在實例化泛型類型的變量時指定的特定類型的佔位符。就是那個list<T>中的T
類型參數的約束:在定義泛型類時,能夠對客戶端代碼可以在實例化類時用於類型參數的類型種類施加限制。 若是客戶端代碼嘗試使用某個約束所不容許的類型來實例化類 ,則會產生編譯時錯誤。 這些限制稱爲約束。 約束是使用 where 上下文關鍵字指定的。 採用「基類、接口、構造器、值類型、引用類型」的約束方式來實現對類型能數 的「顯式約束「, C#泛型要求對「全部泛型類型或泛型方法的類型參數」的任何假定,都要基於「顯示的約束」,以維護C# 所要求的類型安全
1六、請談一下你對同步和異步,多線程的理解。請結合實際場景說明你在項目中的使用狀況。
併發:同時處理多件事情,在處理第一個請求時同時響應第二個請求;
同步:同步就是順序執行,執行完一個再執行下一個,須要等待、協調運行,同步 調用在繼續以前等待響應或返回值。若是不容許調用繼續,就說調用被阻塞 了
異步:併發的一種形式,(1)它採用回調機制,避免產生沒必要要的線程。(2)多線程也能夠成爲實現程序異步的一種方式,在這裏 異步和多線程並非一個同等關係,異步是最終目的,多線程只是咱們實現異步的一種手段(這違反了異步操做的本質)
多線程:併發的另外一種形式,它採用多個線程來執行程序。對多個線程的管理使用了線程池。
並行處理:把正在執行的大量任務,分割成小塊分配個多個運行的線程,線程池是存聽任務的隊列,這個隊列能根據須要自行調整。由此產生了並行處理這個概念,多線程的一種,而多線程是併發的一種
異步優缺點:
由於異步操做無須額外的線程負擔,而且使用回調的方式進行處理,在設計良好的狀況下,處理函數能夠沒必要使用共享變量(即便沒法徹底不用,最起碼能夠減小 共享變量的數量),減小了死鎖的可能。固然異步操做也並不是完美無暇。編寫異步操做的複雜程度較高,程序主要使用回調方式進行處理,與普通人的思惟方式有些出入,並且難以調試。
多線程優缺點:
多線程的優勢很明顯,線程中的處理程序依然是順序執行,符合普通人的思惟習慣,因此編程簡單。可是多線程的缺點也一樣明顯,線程的使用(濫用)會給系統帶來上下文切換的額外負擔。而且線程間的共享變量可能形成死鎖的出現
二者適用範圍:
在瞭解了線程與異步操做各自的優缺點以後,咱們能夠來探討一下線程和異步的合理用途。我認爲:當須要執行I/O操做時,使用異步操做比使用線程+同步 I/O操做更合適。I/O操做不只包括了直接的文件、網絡的讀寫,還包括數據庫操做、Web Service、HttpRequest以及.net Remoting等跨進程的調用。
  而線程的適用範圍則是那種須要長時間CPU運算的場合,例如耗時較長的圖形處理和算法執行。可是每每因爲使用線程編程的簡單和符合習慣,因此不少朋友每每會使用線程來執行耗時較長的I/O操做。這樣在只有少數幾個併發操做的時候還無傷大雅,若是須要處理大量的併發操做時就不合適了。
17 線程池和TPL
線程池能管理不少個線程。和手動建立一個線程來執行特定操做不一樣,咱們將工做任務扔到線程池中,它會選擇合適的線程,而後去執行咱們給定的方法。線程池經過限制建立線程的總數,根據給定的工做量來決定建立合適的線程數量,下降了在極端狀況下,如處理量比較少的狀況下建立和銷燬線程的開銷,幫助咱們解決了對系統資源的獨佔和過分使用。
TPL=>TASK Parallel Library 並行庫,它是基於線程池的, 一種框架要使得並行執行不會產生太多的線程,可以保證工做量可以平均的分配到全部線程上,而且可以報告錯誤和產生可靠地結果,這就是並行庫Task Parallel Library的工做,任務並行化是指經過一系列API將大的任務分解成一系列小的任務,而後再多線程上並行執行 (TPL)並行庫有一系列API可以基於線程池同時管理成千上萬個任務。TPL的核心是System.Threading.Tasks類,他表明一個小的任務,「Task是一種對線程和線程池裏面的工做項的一種結構話抽象
1八、請說明using和new的區別。
new有兩種用法:1.實例化一個對象 2.聲明隱藏方法
一、using導入其它命名空間中定義的類型,這樣,您就沒必要在該命名空間中限定某個類型的使用
二、using爲命名空間或類型建立別名 using Project = PC.MyCompany.Project;  (2)爲類去別名,右邊不能有開放式泛型類型list<T>,必須會LIST<INT>這種  
三、using提供一種能確保正確使用Idisposable對象的比較方便的語法;(idisposable接口有一個方法DIspose()咱們通常用它釋放對象佔用的資源),它定義了一個範圍,在此範圍內的末尾將執行dispose方法(即便範圍內發生異常也會執行dispose()方法)
 1九、 dynamic 動態類型:標記了dynamic標記的表達式在運行時纔會被解析。編譯時,不會被解析。能夠用dynamic表達式調用 類型成員。它的出現方便了開發人員使用反射或者與其餘非c#組建通訊(例如com,例如html dom)。dynamic被編譯後,實際是一個 object類型,只不過編譯器會對dynamic類型進行特殊處理,讓它在編譯期間不進行任何的類型檢查,而是將類型檢查放到了運行期。
 20、反射和序列化:
容許在運行時發現並使用編譯時還不瞭解的類型及成員
1 因爲反射嚴重依賴字符串,形成反射在編譯時沒法保證類型安全,例如Type.GetType("int")
2 反射速度慢,使用反射時類型及其成員的名稱在編譯時未知,你要用字符串名稱標識每一個類型及其成員,而後在運行時發現他們。反射機制會不停的在程序集的元數據中執行字符串搜索,字符串搜索執行的是不區分大小寫的比較。從而影響速度。使用反射調用方法也會影響性能。儘可能避免使用反射來訪問字段或調用方法
反射:程序集包含模塊,而模塊包含類型,類型又包含成員。反射則提供了封裝程序集、模塊和類型的對象。您可使用反射動態地建立類型的實例,將類型綁定到現有對象,或從現有對象中獲取類型。而後,能夠調用類型的方法或訪問其字段和屬性
序列化:序列化是將對象轉換爲容易傳輸的格式的過程。例如,能夠序列化一個對象,而後使用 HTTP 經過 Internet 在客戶端和服務器之間傳輸該對象。在另外一端,反序列化將從該流從新構造對象。
 2一、特性:
特性是爲程序添加元數據的一種機制(存儲在程序文件裏的元數據),特性自己就是用來描述數據的元數據(metadata),經過它能夠給編譯器提供指示或者提供對數據的說明,特性是一個對象,它能夠加載到程序集及程序集的對象中,這些對象包括 程序集自己、模塊、類、接口、結構、構造函數、方法、方法參數等,加載了特性的對象稱做特性的目標。
.net內置的常見特性有:ObsoleteAttribute,使用方式:[Obsolete("該方法已通過期")] 此時在你調用打了標記的方法時,會發出警告消息,來提醒你該方法已通過期
自定義特性:
一、自定義特性類與定義一個類沒有什麼區別,只須要繼承自Attribute基類便可
二、特性類(metadata)自己須要三個特性去描述它Serializable、AttributeUsage 和 ComVisible,因爲特性自己就是用來描述數據的元數據,因此描述元數據的特性被又稱爲元元數據meta-metadata,大多數狀況下咱們只須要掌握AttributeUsage 特性就行了,該特性有三個參數:
ValidOn:這是特性應用位置參數,定義了一個自定義特性可以應用到那種編程元素上,是方法仍是屬性
AllowMultiple:命名參數,它指定一個特性可否在一個程序集中被屢次使用
Inherited:命名參數,用於控制一個自定義特性是否能被該類型的子類繼承
其中,位置參數ValidOn使用AttributeTargets枚舉
例如:[AttributeUsage(AttributeTargets.Method)] //控制自定義特性的使用,該特性就只能用於方法上面{能夠不設置}
通常經過反射來遍歷檢查應用的特性信息,咱們能夠藉助該信息來作權限,安全,登陸狀態驗證
21 擴展方法:
若是要給已編譯好的類添加新功能,開發人員通常只能從這個類中派生一個基類,或者更改這個類的源代碼方式;
擴展方法的出現解決了這個問題,咱們能夠在一個單獨的類中對已經存在的類進行擴展,爲其添加擴展方法並不須要對源代碼進行改動或繼承基類
定義擴展方法:
* 一、擴展方法必需要定義到一個靜態類中,擴展方法自己也必須是靜態的
* 二、擴展方法首個參數必須是this 後面緊跟擴展的類 如:static void fun (this int i)
* 三、擴展方法能夠被正確的對象實例調用 也可使用靜態類名進行靜態調用
* 四、擴展方法的名稱不能與要擴展的類名相同 編譯時,擴展方法的優先級要低於擴展類自己方法的優先級
* 五、不能再擴展方法中直接訪問擴展類的成員變量
2二、 表達式樹
表達式樹提供一個將可執行代碼轉換成數據的方法,若是你要在執行代碼以前修改或轉換此代碼他將變得頗有價值。
表達式樹被建立是爲了製造一個像將查詢表達式轉換成字符串以傳遞給其餘程序並在那裏執行這樣的轉換任務。把代碼,轉換成數據,而後分析數據發現其組成部分,最後轉換成能夠傳遞到其餘程序的字符串,Linq to SQL,實際上它就是C#做爲源語言,SQL做爲目標語言的一個編譯過程, 一個LINQ to SQL查詢不是在你的C#程序裏執行的。它會被轉換成SQL,經過網絡發送,最後在數據庫服務器上執行
表單式樹有四個屬性:
* Body:獲得表達式的主體
* Parameters:獲得lambda表達式的參數
* NodeType:獲取樹的節點的ExpressionType共45種不一樣值,包含全部表達式節點各類可能的類型,例如返回常量,例如返回參數,例如取兩個值的小值(<),例如取兩個值的大值(>),例如將值相加(+),等等。
 
2三、在平常開發中你經常使用哪些設計模式?分別解決什麼問題?請結合實際場景說明你在項目中的使用狀況。
簡單工廠、工廠方法、策略模式、抽象工廠模式、單利模式(將對象的構造函數設置爲私有的,阻止外界直接實例化它,必須經過訪問靜態實例化屬性/方法來建立)
24 CLR名詞解釋
CLR(common language runtime)公共語言運行時:clr 公共語言運行時,核心功能是內存管理,程序集加載,安全性,異常處理和線程同步。面向clr的全部語言均可以使用核心功能。在運行時clr不關心開發人員使用的是什麼語言開發的源代碼,由於針對每種語言都有一個面向clr的代碼編譯器,例如c#有針對c#的編譯器,c++也有它本身的編譯器。編譯器將其最終生成託管模塊。
託管模塊: 託管模塊是32位或者64位的windows可移植執行體pe32文件。須要clr才能運行。它包含四部份內容
程序集和託管模塊:clr實際不和託管模塊工做,它和程序集工做。程序集是一個抽象概念,他是一個或多個託管模塊/資源文件的邏輯分組,程序集是重用和安全性以及版本控制的最小單元
託管代碼和非託管代碼:
在CLR監視下運行的程序屬於「託管代碼」,而再也不CLR監視下直接在裸機上運行的程序屬於「非託管代碼」,非託管代碼能夠對系統進行低級控制,能夠按照本身的想法管理內存,更方便的建立線程。c++編譯器默認生成包含非託管代碼的模塊,並在運行時操做非託管內存數據。這些模塊不須要clr就可運行,c++的編譯器是獨一無二的,它容許開發人員同時寫託管代碼和非託管代碼,並生成到同一模塊中。
FCL(framework class library) framework類庫:
是一組DLL程序集的統稱,是微軟發佈的數千個類型的定義,包含了不少輔助功能。開發人員能夠利用這些程序集建立應用程序,例如:windows控制檯,windows服務,web應用等
CTS (common type system) 通用類型系統:
CLR一切都圍繞類型展開,類型嚮應用程序和其餘類型公開功能,類型是clr的根本,因此微軟制訂了正式的規範來描述類型的定義和行爲;例如cts規範規定了一個類型能夠有0個或多個成員,成員包括字段,方法,屬性,事件。cts他還規定了類型和成員的訪問規則,例如標記爲public仍是product等。
CLS (common language specification)公共語言運行規範:
CLR集成了全部的語言,用一個語言建立的對象在另一個語言中具備和它本身語言建立的對象同等的地位,可是各類語言在語法上存在很大差異,要建立其餘語言都能訪問的類型只能從自身語言牀挑選其餘語言可識別的功能;微軟提供了一種語法規則,凡是符合cls公共語言容許規範的功能就能在其餘語言中一樣符合其規範的功能訪問。它是cts/clr的一個子集。
 
 
實踐題:
相關文章
相關標籤/搜索