c# .net 面試總結

一. sql優化

1. 寫明查詢具體某幾列,減小*的使用,表名過長時,儘可能使用表的別名 *和列名同樣

2,在業務密集的SQL當中儘可能不採用IN操做符,用EXISTS 方案代替。

  in 和 exists的區別: 若是子查詢得出的結果集記錄較少,主查詢中的表較大且又有索引時應該用in, 反之若是外層的主查詢記錄較少,子查詢中的表大,又有索引時使用exists。其實咱們區分in和exists主要是形成了驅動順序的改變(這是性能變化的關鍵),若是是exists,那麼之外層表爲驅動表,先被訪問,若是是IN,那麼先執行子查詢,因此咱們會以驅動表的快速返回爲目標,那麼就會考慮到索引及結果集的關係了 ,另外IN時不對NULL進行處理。

  in 是把外表和內表做hash 鏈接,而exists是對外表做loop循環,每次loop循環再對內表進行查詢。一直以來認爲exists比in效率高的說法是不許確的。

3、模糊查詢like,儘可能少用%
  關鍵詞%yue%,因爲yue前面用到了「%」,所以該查詢必然走全表掃描,除非必要,不然不要在關鍵詞前加%4, 兩者都能使用盡可能使用where (與having比較)
  where 先過濾(數據就少了)再分組  
5,儘可能使用多表鏈接(join)查詢(避免子查詢)

  子查詢效率特別低,而通常的子查詢均可以由關連查詢來實現相同的功能,關聯查詢的效率要提升不少,因此建議在數據查詢時避免使用子查詢(尤爲是在記錄不少時),而最好用關聯查詢來實現。

6,創建索引

  較頻繁地做爲查詢條件的字段,惟一性不太差的字段適合創建索引,更新不太頻繁地字段適合建立索引,不會出如今where條件中的字段不應創建索引

7,多使用內部函數提升SQL效率

  例如多用concat鏈接,代替'||' 的符號鏈接

8,應儘可能避免在 where 子句中使用 != 或 <> ,in 或 not in

  最好不要給數據庫留NULL,儘量的使用 NOT NULL填充數據庫 (否則會進行全表掃描,影響效率) 

9,儘量的使用 varchar/nvarchar 代替 char/nchar (節省字段存儲空間)
View Code

二.接口和類有什麼異同,抽象類和接口有什麼區別

接口和類有什麼異同
不一樣點:

1、接口不能直接實例化。

2、接口只包含方法或屬性的聲明,不包含方法的實現。

3、接口能夠多繼承,類只能單繼承。

4、類有分部類的概念,定義可在不一樣的源文件之間進行拆分,而接口沒有。(這個地方確實不對,接口也能夠分部,謝謝@xclin163的指正)

5、表達的含義不一樣,接口主要定義一種規範,統一調用方法,也就是規範類,約束類,類是方法功能的實現和集合

相同點:

1、接口、類和結構均可以從多個接口繼承。

2、接口相似於抽象基類:繼承接口的任何非抽象類型都必須實現接口的全部成員。

3、接口和類均可以包含事件、索引器、方法和屬性。

抽象類和接口有什麼區別
1、繼承:接口支持多繼承;抽象類不能實現多繼承。

2、表達的概念:接口用於規範,更強調契約,抽象類用於共性,強調父子。抽象類是一類事物的高度聚合,那麼對於繼承抽象類的子類來講,對於抽象類來講,屬於"Is A"的關係;而接口是定義行爲規範,強調「Can Do」的關係,所以對於實現接口的子類來講,相對於接口來講,是"行爲須要按照接口來完成"3、方法實現:對抽象類中的方法,便可以給出實現部分,也能夠不給出;而接口的方法(抽象規則)都不能給出實現部分,接口中方法不能加修飾符。

4、子類重寫:繼承類對於二者所涉及方法的實現是不一樣的。繼承類對於抽象類所定義的抽象方法,能夠不用重寫,也就是說,能夠延用抽象類的方法;而對於接口類所定義的方法或者屬性來講,在繼承類中必須重寫,給出相應的方法和屬性實現。

5、新增方法的影響:在抽象類中,新增一個方法的話,繼承類中能夠不用做任何處理;而對於接口來講,則須要修改繼承類,提供新定義的方法。

6、接口能夠做用於值類型(枚舉能夠實現接口)和引用類型;抽象類只能做用於引用類型。

7、接口不能包含字段和已實現的方法,接口只包含方法、屬性、索引器、事件的簽名;抽象類能夠定義字段、屬性、包含有實現的方法。
View Code

三.C#中的委託是什麼?事件是否是一種委託?

什麼是委託?簡單來講,委託相似於 C或 C++中的函數指針,容許將方法做爲參數進行傳遞。

C#中的委託都繼承自System.Delegate類型;
委託類型的聲明與方法簽名相似,有返回值和參數;
委託是一種能夠封裝命名(或匿名)方法的引用類型,把方法當作指針傳遞,但委託是面向對象、類型安全的;
事件能夠理解爲一種特殊的委託,事件內部是基於委託來實現的。
View Code

四.GC與內存管理

1. 簡述一下一個引用對象的生命週期?
new建立對象並分配內存
對象初始化
對象操做、使用
資源清理(非託管資源)
GC垃圾回收
2. GC進行垃圾回收時的主要流程是?
① 標記:先假設全部對象都是垃圾,根據應用程序根Root遍歷堆上的每個引用對象,生成可達對象圖,對於還在使用的對象(可達對象)進行標記(其實就是在對象同步索引塊中開啓一個標示位)。

② 清除:針對全部不可達對象進行清除操做,針對普通對象直接回收內存,而對於實現了終結器的對象(實現了析構函數的對象)須要單獨回收處理。清除以後,內存就會變得不連續了,就是步驟3的工做了。

③ 壓縮:把剩下的對象轉移到一個連續的內存,由於這些對象地址變了,還須要把那些Root跟指針的地址修改成移動後的新地址。

6. GC在哪些狀況下回進行回收工做?
內存不足溢出時(0代對象充滿時)
Windwos報告內存不足時,CLR會強制執行垃圾回收
CLR卸載AppDomian,GC回收全部
調用GC.Collect
其餘狀況,如主機拒絕分配內存,物理內存不足,超出短時間存活代的存段門限
7. using() 語法是如何確保對象資源被釋放的?若是內部出現異常依然會釋放資源嗎?
using() 只是一種語法形式,其本質仍是try…finally的結構,能夠保證Dispose始終會被執行。

8. 解釋一下C#裏的析構函數?爲何有些編程建議裏不推薦使用析構函數呢?
C#裏的析構函數其實就是終結器Finalize,由於長得像C++裏的析構函數而已。

有些編程建議裏不推薦使用析構函數要緣由在於:第一是Finalize自己性能並很差;其次不少人搞不清楚Finalize的原理,可能會濫用,致使內存泄露,所以就乾脆別用了

9. Finalize() 和 Dispose() 之間的區別?
Finalize() 和 Dispose()都是.NET中提供釋放非託管資源的方式,他們的主要區別在於執行者和執行時間不一樣:

finalize由垃圾回收器調用;dispose由對象調用。
finalize無需擔憂由於沒有調用finalize而使非託管資源得不到釋放,而dispose必須手動調用。
finalize不能保證當即釋放非託管資源,Finalizer被執行的時間是在對象再也不被引用後的某個不肯定的時間;而dispose一調用便釋放非託管資源。
只有class類型才能重寫finalize,而結構不能;類和結構都能實現IDispose。
另一個重點區別就是終結器會致使對象復活一次,也就說會被GC回收兩次才最終完成回收工做,這也是有些人不建議開發人員使用終結器的主要緣由。

10. Dispose和Finalize方法在什麼時候被調用?
Dispose一調用便釋放非託管資源;
Finalize不能保證當即釋放非託管資源,Finalizer被執行的時間是在對象再也不被引用後的某個不肯定的時間;
11. .NET中的託管堆中是否可能出現內存泄露的現象?
是的,可能會。好比:

不正確的使用靜態字段,致使大量數據沒法被GC釋放;
沒有正確執行Dispose(),非託管資源沒有獲得釋放;
不正確的使用終結器Finalize(),致使沒法正常釋放資源;
其餘不正確的引用,致使大量託管對象沒法被GC釋放;
12. 在託管堆上建立新對象有哪幾種常見方式?
new一個對象;
字符串賦值,如string s1=」abc」;
值類型裝箱;
View Code

五.多線程編程與線程同步

1. 描述線程與進程的區別?
一個應用程序實例是一個進程,一個進程內包含一個或多個線程,線程是進程的一部分;
進程之間是相互獨立的,他們有各自的私有內存空間和資源,進程內的線程能夠共享其所屬進程的全部資源;
2. lock爲何要鎖定一個參數,可不可鎖定一個值類型?這個參數有什麼要求?
lock的鎖對象要求爲一個引用類型。她能夠鎖定值類型,但值類型會被裝箱,每次裝箱後的對象都不同,會致使鎖定無效。

對於lock鎖,鎖定的這個對象參數纔是關鍵,這個參數的同步索引塊指針會指向一個真正的鎖(同步塊),這個鎖(同步塊)會被複用。

3. 多線程和異步有什麼關係和區別?
多線程是實現異步的主要方式之一,異步並不等同於多線程。實現異步的方式還有不少,好比利用硬件的特性、使用進程或纖程等。在.NET中就有不少的異步編程支持,好比不少地方都有Begin***、End***的方法,就是一種異步編程支持,她內部有些是利用多線程,有些是利用硬件的特性來實現的異步編程。

4. 線程池的優勢有哪些?又有哪些不足?
優勢:減少線程建立和銷燬的開銷,能夠複用線程;也從而減小了線程上下文切換的性能損失;在GC回收時,較少的線程更有利於GC的回收效率。

缺點:線程池沒法對一個線程有更多的精確的控制,如瞭解其運行狀態等;不能設置線程的優先級;加入到線程池的任務(方法)不能有返回值;對於須要長期運行的任務就不適合線程池。

5. Mutex和lock有何不一樣?通常用哪個做爲鎖使用更好?
Mutex是一個基於內核模式的互斥鎖,支持鎖的遞歸調用,而Lock是一個混合鎖,通常建議使用Lock更好,由於lock的性能更好。
View Code

 關於線程和併發相關的這邊提供幾篇不錯的文章html

  http://www.cnblogs.com/yunfeifei/p/3993401.htmlsql

  http://www.javashuo.com/article/p-fcveujac-dq.html數據庫

六.重載與覆蓋的區別

重載:當類包含兩個名稱相同但簽名不一樣(方法名相同,參數列表不相同)的方法時發生方法重載。用方法重載來提供在語義上完成相同而功能不一樣的方法。

覆寫:在類的繼承中使用,經過覆寫子類方法能夠改變父類虛方法的實現。

主要區別:

1、方法的覆蓋是子類和父類之間的關係,是垂直關係;方法的重載是同一個類中方法之間的關係,是水平關係。 
2、覆蓋只能由一個方法,或只能由一對方法產生關係;方法的重載是多個方法之間的關係。 
3、覆蓋要求參數列表相同;重載要求參數列表不一樣。 
4、覆蓋關係中,調用那個方法體,是根據對象的類型來決定;重載關係,是根據調用時的實參表與形參表來選擇方法體的。
View Code

七.virtual、sealed、override和abstract的區別

virtual申明虛方法的關鍵字,說明該方法能夠被重寫
sealed說明該類不可被繼承
override重寫基類的方法
abstract申明抽象類和抽象方法的關鍵字,抽象方法不提供實現,由子類實現,抽象類不可實例化。
View Code

八.裝箱與拆箱

1.什麼是拆箱和裝箱?

裝箱就是值類型轉換爲引用類型,拆箱就是引用類型(被裝箱的對象)轉換爲值類型。

2.什麼是箱子?

就是引用類型對象。

3.箱子放在哪裏?

託管堆上。

4.裝箱和拆箱有什麼性能影響?

裝箱和拆箱都涉及到內存的分配和對象的建立,有較大的性能影響。

5.如何避免隱身裝箱?

編碼中,多使用泛型、顯示裝箱。

6.箱子的基本結構?

上面說了,箱子就是一個引用類型對象,所以她的結構,主要包含兩部分:
值類型字段值;
引用類型的標準配置,引用對象的額外空間:TypeHandle和同步索引塊,關於這兩個概念在本系列後面的文章會深刻探討。

7.裝箱的過程?

1.在堆中申請內存,內存大小爲值類型的大小,再加上額外固定空間(引用類型的標配:TypeHandle和同步索引塊);
2.將值類型的字段值(x=1023)拷貝新分配的內存中;
3.返回新引用對象的地址(給引用變量object o)

8.拆箱的過程?

1.檢查實例對象(object o)是否有效,如是否爲null,其裝箱的類型與拆箱的類型(int)是否一致,如檢測不合法,拋出異常;
2.指針返回,就是獲取裝箱對象(object o)中值類型字段值的地址;
3.字段拷貝,把裝箱對象(object o)中值類型字段值拷貝到棧上,意思就是建立一個新的值類型變量來存儲拆箱後的值;
View Code

九.什麼是反射

程序集包含模塊,而模塊又包括類型,類型下有成員,反射就是管理程序集,模塊,類型的對象,它可以動態的建立類型的實例,設置現有對象的類型或者獲取現有對象的類型,能調用類型的方法和訪問類型的字段屬性。它是在運行時建立和使用類型實例;
事例

   public class ReflectionTest {
        
        /// <summary>
        /// 反射名稱
        /// </summary>
        public string ReflectionName { get; set; }

        public string GetName()
        {
            return "張三";
        }
    }


   Type type = typeof(ReflectionTest);
            string name = type.Name;//獲取當前成員的名稱
            string fullName = type.FullName;//獲取類的所有名稱不包括程序集
            string nameSpace = type.Namespace;//獲取該類的命名空間
            var assembly = type.Assembly;//獲取該類的程序集名
            var module = type.Module;//獲取該類型的模塊名            
            var memberInfos = type.GetMembers();//獲得全部公共成員
   
 //獲取當前執行代碼的程序集
            Assembly assem = Assembly.GetExecutingAssembly();
            Console.WriteLine(assem.FullName);

            var types = assem.GetTypes();//程序集下全部的類
            Console.WriteLine("程序集包含的類型:");
            foreach (var item in types) {
                Console.WriteLine("" + item.Name);
            }
View Code

十.數據庫常見的操做--事務,存儲過程,遊標,觸發器等

1.維護數據庫的完整性、一致性、你喜歡用觸發器仍是自寫業務邏輯?爲何?

答:儘量用約束(包括CHECK、主鍵、惟一鍵、外鍵、非空字段)實現,這種方式的效率最好;其次用觸發器,這種方式能夠保證不管何種業務系統訪問數據庫都能維持數據庫的完整性、一致性;最後再考慮用自寫業務邏輯實現,但這種方式效率最低、編程最複雜,當爲下下之策。

2.什麼是事務?什麼是鎖?

答:事務是指一個工做單元,它包含了一組數據操做命令,而且全部的命令做爲一個總體一塊兒向系統提交或撤消請求操做,即這組命令要麼都執行,要麼都不執行。

  鎖是在多用戶環境中對數據的訪問的限制。SqlServer自動鎖定特定記錄、字段或文件,防止用戶訪問,以維護數據安全或防止併發數據操做問題,鎖能夠保證事務的完整性和併發性。

 3.什麼是索引,有什麼優勢?

答:索引象書的目錄相似,索引使數據庫程序無需掃描整個表,就能夠在其中找到所須要的數據,索引包含了一個表中包含值的列表,其中包含了各個值的行所存儲的位置,索引能夠是單個或一組列,索引提供的表中數據的邏輯位置,合理劃分索引可以大大提升數據庫性能。

 4.視圖是什麼?遊標是什麼?

答:視圖是一種虛擬表,虛擬表具備和物理表相同的功能,能夠對虛擬表進行增該查操做;

    視圖一般是一個或多個表的行或列的子集;

   視圖的結果更容易理解(修改視圖對基表不影響),獲取數據更容易(相比多表查詢更方便),限制數據檢索(好比須要隱藏某些行或列),維護更方便。

   遊標對查詢出來的結果集做爲一個單元來有效的處理,遊標能夠定位在結果集的特定行、從結果集的當前位置檢索一行或多行、能夠對結果集中當前位置進行修改、

 5.什麼是存儲過程?有什麼優勢?

答:存儲過程是一組予編譯的SQL語句

    它的優勢:1.容許模塊化程序設計,就是說只須要建立一次過程,之後在程序中就能夠調用該過程任意次。

              2.容許更快執行,若是某操做須要執行大量SQL語句或重複執行,存儲過程比SQL語句執行的要快。

               3.減小網絡流量,例如一個須要數百行的SQL代碼的操做有一條執行語句完成,不須要在網絡中發送數百行代碼。

        4.更好的安全機制,對於沒有權限執行存儲過程的用戶,也可受權他們執行存儲過程。

 6.什麼是觸發器?

答:觸發器是一種特殊類型的存儲過程,出發器主要經過事件觸發而被執行的,

  觸發器的優勢:1.強化約束,觸發器可以提供比CHECK約束;

         2.跟蹤變化,觸發器能夠跟蹤數據庫內的操做,從而不容許未經容許許可的更新和變化;

         3.聯級運算,好比某個表上的觸發器中包含對另外一個表的數據操做,而該操做又致使該表上的觸發器被觸發
View Code

 

後續還會慢慢補充,本身碰到或者看到比較好的一些知識都會一一記錄下來  若是有好的知識點 你們記得分享哦編程

相關文章
相關標籤/搜索