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

六.重載與覆蓋的區別

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

覆寫:在類的繼承中使用,通過覆寫子類方法可以改變父類虛方法的實現。

主要區別:

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

   後續還會慢慢補充,自己碰到或者看到比較好的一些知識都會一一記錄下來  如果有好的知識點 大家記得分享哦

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章