C# 常見面試問題匯總


1、c#垃圾回收機制

    從以下方面入手展開:  1、壓縮合並算法   2、代的機制  3、GC調用終結器 Garbage Collector

   . NET采用了和Java類似的方法由CLR(Common Language Runtime)來管理 

     .NET的GC機制有這樣兩個問題:

  首先,GC並不是能釋放所有的資源。它不能自動釋放非托管資源。

  第二,GC並不是實時性的,這將會造成系統性能上的瓶頸和不確定性。

  GC並不是實時性的,這會造成系統性能上的瓶頸和不確定性。所以有了IDisposable接口,IDisposable接口定義了Dispose方法,這個方法用來供程序員顯式調用以釋放非托管資源。使用using語句可以簡化資源管理。

       具體詳見:https://www.cnblogs.com/nele/p/5673215.html

2、委托和事件

     先說它的定義:委托的本質是類,類型安全的指針,然后從用途上考慮,事件是包裝的委托,但事件不是委托。事件是由一個私有委托和add、remove 方法組成。

     事件、索引器、屬性本質都是方法。接口只可以定義方法。所以接口也可以定義“事件、索引器、屬性”,因為他們的本質也是add、remove 方法。

     委托是一種可以指向方法的數據類型,可以聲明委托類型變量。

     聲明委托的方式:delegate返回值類型   委托類型名(參數)

     比如delegate void MyDel(int n) 。C#中默認寫了2中委托Action<>,Func<>,Action基本上都是void沒有返回值,Func是有返回值的

    

 1 using System.Collections.Generic;
 2 using System.Linq;
 3 using System.Text;
 4 using System.Threading.Tasks;
 5 
 6 namespace TestConsole
 7 {
 8     delegate void MyDel();
 9     class Program
10     {
11 
12         static void Main(string[] args)
13         {
14             person p = new person();
15             p.QingZhu += ShowMsg;
16             p.age = 24;
17             Console.ReadKey();
18         }
19         static void ShowMsg()
20         {
21             Console.WriteLine("今年是你的本命年!恭喜你");
22         }
23     }
24     class person
25     {
26         private int Age;
27         public int age
28         {
29             get
30             {
31                 return age;
32             }
33             set
34             {
35                 if (value % 12 == 0)
36                 {
37                     if (QingZhu != null)
38                     {
39                         QingZhu();//執行事件
40                     }
41                 }
42             }
43         }
44         public event MyDel  QingZhu;
45     }
46 }
View Code

 

 1 using System;
 2 using System.Collections;
 3 using System.Collections.Generic;
 4 using System.Linq;
 5 using System.Text;
 6 using System.Threading.Tasks;
 7 
 8 namespace TestConsole
 9 {
10     delegate void MyDel();
11     class Program
12     {
13 
14         static void Main(string[] args)
15         {
16             person p = new person();
17             p.qingzhu += ShowMsg;
18             p.age = 24;
19             Console.ReadKey();
20         }
21         static void ShowMsg()
22         {
23             Console.WriteLine("今年是你的本命年!恭喜你");
24         }
25     }
26     class person
27     {
28         private int Age;
29         public int age
30         {
31             get
32             {
33                 return age;
34             }
35             set
36             {
37                 if (value % 12 == 0)
38                 {
39                     if (this.QingZhu != null)
40                     {
41                         this.QingZhu();//執行事件
42                     }
43                 }
44             }
45         }
46         private  MyDel  QingZhu;
47         public event MyDel qingzhu
48         {
49             add
50             {
51                 this.QingZhu += value;
52             }
53             remove
54             {
55                 this.QingZhu -= value;
56             }
57         }
58 
59     }
60 }
View Code

3、c#索引

    索引可以是字符串類型的,可以允許有多個索引參數,下面的方法我就可以定義多個參數。常見的Dictory<string,string>也是索引的一種。在IL中本質其實是Get_Item 方法(無參數)、Set_Item 方法(參數:value)。

 1 class MyIntIndex
 2     {
 3         private static string[] name = { "dandan", "chizi", "jianguo" };
 4         public string this[int index]
 5         {
 6             get
 7             {
 8                 string n = name[index];
 9                 return n;
10             }
11             set
12             {
13                 name[index] = value;
14             }
15         }
16     }
17 }
View Code

4、裝箱和拆箱

    值類型和引用類型之間的轉換。頻繁裝箱和拆箱會導致系統性能降低,可考慮用泛型。值類型賦值給object為裝箱操作,值類型賦值給object拆箱(顯示轉換)。裝什么類型拆箱就是什么類型,除非C#中convert.toInt32 等內置的這些方法可以強制拆箱。

5、泛型

   考得不多,但我們平常用的比較多。所以對泛型的一些東西需要了解,如泛型約束等。 

   泛型約束 public void GetEntity<T>() where T:class

    where T :struct //約束T必須為值類型
    where K : class //約束K必須為引用類型
    where V : IComparable //約束V必須是實現了IComparable接口
    where W : K //要求W必須是K類型,或者K類型的子類
    where X :class ,new () // 或者寫出 new class() ;   X必須是引用類型,並且要有一個無參的構造函數(對於一個類型有多有約束,中間用逗號隔開)

6、c#如何調用c++ 的dll?為什么可以調用

     右擊添加類中的“TypeLib中的MFC類”選項實現跨平台調用。添加好后會生成h文件和cpp文件

   tjdmwj2tjdmwj3tjdmwj4

   填寫完后Function.h文件會報錯,錯誤類型如下。這里需要在C++項目里面設置,讓動態庫受到公共語言運行時的支持。如下圖所示:打開項目屬性

   tjdmwj4tjdmwj5tjdmwj6

     C#和C++在vs中的語法類型都會編譯成CTS(Common Type System通用數據類型)生成.net 中有CLS(Common Language Specification公共語言允規范) 並在IL代碼中的CLR(Common Language Runtime 公共語言運行池)中運行。

     Int和Int32,string與String的區別,一個是C#代碼中的類型,一個是IL中的CTS通用數據類型

7、托管資源和非托管資源

    問題:1、定義  2、如何釋放

   托管資源是指由CLR管理分配和釋放的資源。托管資源有GC釋放,非托管資源由程序員自己釋放,可以實現dispose接口。

   關於托管資源,就不用說了撒,像簡單的int,string,float,DateTime等等,.net中超過80%的資源都是托管資源。

   非托管資源如何釋放,.NET Framework 提供 Object.Finalize 方法,它允許對象在垃圾回收器回收該對象使用的內存時適當清理其非托管資源。

   值類型在棧內存中,方法結束自動釋放,引用類型在堆內存中需要GC來回收

   

~MyClass()
{
  // Perform some cleanup operations here.
}
  該代碼隱式翻譯為下面的代碼。
protected override void Finalize()
{
  try
  {
    // Perform some cleanup operations here.
  }
  finally
  {
    base.Finalize();
  }
}

 

在一個包含非托管資源的類中,關於資源釋放的標准做法是:

(1) 繼承IDisposable接口;

(2) 實現Dispose()方法,在其中釋放托管資源和非托管資源,並將對象本身從垃圾回收器中移除(垃圾回收器不在回收此資源);

(3) 實現類析構函數,在其中釋放非托管資源。

 

 1 PublicclassBaseResource:IDisposable
 2 {
 3   PrivateIntPtr handle; // 句柄,屬於非托管資源
 4   PrivateComponet comp; // 組件,托管資源
 5   Privateboo isDisposed = false;// 是否已釋放資源的標志
 6    PublicBaseResource()
 7    {
 8    }
 9    //實現接口方法
10    //由類的使用者,在外部顯示調用,釋放類資源
11    Publicvoid Dispose()
12    {
13      Dispose(true);// 釋放托管和非托管資源
14      //將對象從垃圾回收器鏈表中移除,
15     // 從而在垃圾回收器工作時,只釋放托管資源,而不執行此對象的析構函 
16 17     GC.SuppressFinalize(this);
18     }
19     //由垃圾回收器調用,釋放非托管資源
20     ~BaseResource()
21      {
22       Dispose(false);// 釋放非托管資源
23      }
24     //參數為true表示釋放所有資源,只能由使用者調用
25     //參數為false表示釋放非托管資源,只能由垃圾回收器自動調用
26    //如果子類有自己的非托管資源,可以重載這個函數,添加自己的非托管 
27     資源的釋放
28    //但是要記住,重載此函數必須保證調用基類的版本,以保證基類的資源 
29     正常釋放
30     Protected virtual void Dispose(booldisposing)
31    {
32      If(!this.disposed)// 如果資源未釋放 這個判斷主要用了防止對象被多 
33 34       釋放
35     {
36      If(disposing)
37      {
38       Comp.Dispose();// 釋放托管資源
39      }
40        closeHandle(handle);// 釋放非托管資源
41        handle= IntPtr.Zero;
42       }
43       this.disposed=true;// 標識此對象已釋放
44     }
45 }
View Code

 

8、MVC原理

   路由機制,我覺得此題,根據自己的理解回答即可,可深入回答  從view上請求到controller組織model,反映到view上.詳細框架原理,可以查看:https://blog.csdn.net/jehuyang/article/details/100575686

9、MVC中,后台向前台頁面傳對象的方式

   強類型的模型綁定、ViewData、ViewBag 。其中ViewData是ViewDataDictory類型,而VieBag是dynamic類型. dynamic 可以動態給不同的類型。例如:dynamic p1=new Expandobject(); p1.Age=10; p1.Age="222";這樣也不會報錯。

10、MVC中過濾器

   Filter過濾器.AOP 面向切面編程。

   IAuthorizationFilter 一般檢查用戶是否有Action執行權限。在每個Action之前執行OnAuthorization方法。

   IActionFilter在每個Action之前執行OnActionExcuting方法,在每個Action執行完成后執行OnActionExecuted 方法. IAuthorizationFilter在IActionFilter執行之前執行,所以檢查權限一般寫在IAuthorizationFilter中的OnAuthorization方法中。

   IResultFilter在每個ActionResult的前后執行,一般很少用

   IExceptionFilter當每個Action有未處理的異常執行OnException 方法。MVC中可以使用Application_Error,但建議使用IExceptionFilter方法。

   定義的類可以在Global中Global.Filters.Filter.Add(new XXXFilter())添加使用。

11、c#擴展方法如何寫?

    靜態類+靜態方法+this,例如下面代碼:

class Program
    {
        static void Main(string[] args)
        {
            string str = "Hello World!";
            str.ShowMsg(str);
            Console.ReadKey();
        }
  }
    #region 擴展方法
    static class MyString
    {
        public static void ShowMsg(this string a, string msg)
        {
            Console.WriteLine(msg);
        }
    }
    #endregion 擴展方法

12、.NET Core Api 安全驗證以及中間件 (本人沒有了解過,代深入了解

     采用jwt,生成token驗證,比如我們用來錯誤處理的中間件,可以定義其它功能的中間件。了解詳細頁面:https://www.cnblogs.com/savorboard/p/aspnetcore-authentication.html

13、設計模式(本人沒有了解過,代深入了解)

     常用的設計模式:工廠、抽象工廠、代理、適配器、模板、策略、單例、觀察者等,根據自己在項目中的使用情況,可以談一談。介紹鏈接:https://www.cnblogs.com/mq0036/p/8288099.html

14、單點登錄

      單點登錄(Single Sign On),簡稱為 SSO,是目前比較流行的企業業務整合的解決方案之一。SSO的定義是在多個應用系統中,用戶只需要登錄一次就可以訪問所有相互信任的應用系統。使用“單點登錄”整合后,只需要登錄一次就可以進入多個系統,而不需要重        新登錄,這不僅僅帶來了更好的用戶體驗,更重要的是降低了安全的風險和管理的消耗。介紹鏈接:https://www.cnblogs.com/yueshutong/p/9468035.html

15、聚集索引和非聚集索引

      聚集索引:也叫聚簇(cu)索引。數據行的物理順序與列值(一般是主鍵的那一列)的邏輯順序相同,一個表中只能擁有一個聚集索引。

      非聚集索引:該索引中索引的邏輯順序與磁盤上行的物理存儲順序不同,一個表中可以擁有多個非聚集索引。

16、char,varchar、nvarchar區別   

char 

char是定長的,這個怎么說呢,比如你用char(10),當你輸入6個字符時,它會用英文的空格給補全。當你輸入的15個字符時,它會自動截取前10個字符。取值范圍1-8000

優點:適合存儲定長的數據,存儲效率快

缺點:使用不當會造成存儲空間的浪費
varchar

varchar可變長度的,存儲的大小為輸入數據的字節的實際長度,所輸入的數據字符長度可以為0。取值范圍0-8000

優點:適合存儲不固定長度的數據,它可以識別出字節用於保存實際使用多大的長度。合理的利用的存儲空間。

缺點:存儲效率低

nvarchar

我們都知道英文字母占一個字節,漢字占兩個字節,如果我們的數據中又有英文,又有漢字,這時nvarchar就該上場了,nvarchar無論是英文還是漢字都是用兩個字節來表示。

優點:適合存儲既有英文和漢字的數據

缺點:它最多能存儲4000個字符,對英文存儲上有些損失

17、數據庫死鎖產生的原因及解決辦法(本人沒有了解過,代深入了解)

      兩個進程各自占有資源,然后它們都還想得到對方的資源,而自己不肯釋放資源。我覺得死鎖的活該,誰叫你那么貪婪。

18、有用過緩存嗎?有用過redis嗎?

     你若回答用過,面試官繼續追問;你若回答沒用過,他會覺得這都沒有用過。

     緩存為了提高應用程序性能,因為請求數據庫的次數少了。redis有很多特點:1、key-value   2、內存數據庫,可以持久化到硬盤上  3、可以用作消息隊列

19、IOC、依賴注入、容器

      IOC是一種思想,控制反轉,反轉的是對象的控制權,把生成對象的權利交到外部。比如在方法中要使用一個Student對象,有三種方法,1、用的時候,直接New一個對象  2、從方法參數中傳入Student對象   3、從容器中獲取一個Student對象

20、大文件上傳與下載,如何考慮?比如說50G的大文件

      可以分段下載,webconfig中必須配置大小。具體沒有研究過待研究       

21、Linq

22、AOP

    面向切面的編程。比如給每個Controller,添加日志功能,AOP是橫向思維的一種體現。和問題10有重復

23、SOA、Webservice、WCF  (具體沒有研究過待研究 )      

    問題:Webservice與WCF區別

    WCF是一個統一的框架,包括了remotting、Webservice,msmq,可以采用tcp和http等協議。也可以進行安全設置和驗證。缺點:配置復雜

24、有研究過Docker嗎

    Docker是一個平台,解決部署問題。需要理解Image(鏡像)和Container的關系,了解運行機理

25、有研究過微服務嗎

26、sql性能優化

      查看sql執行計划、拆庫、拆表、優化語句等

27、你了解串口編程嗎

     就是控制攝像頭之類的設備編程,得了解計算機的基本原理

28、js字符串和數組相互轉化

29、請設計一個遞歸算法

      比如5的階乘,遞歸算法的一個要點是要設置結束條件,否則會棧溢出。

30、如何考慮做一個網站

31、線性表和鏈表的區別

32、談談你對js閉包的理解

33、多線程中的同步、異步、Task

     異步主要為了提升吞吐量,防止阻塞。Task主要提供了一個管理線程的接口,比如獲取線程的結果、狀態、取消線程的執行等

34、用過NoSql嗎

    redis  、Memcached、MongoDB等

    redis 的優點: 

       1)  支持 string、list、set、geo 等復雜的數據結構。

       2)  高命中的數據運行時是在內存中,數據最終還是可以保存到磁盤中,這樣服務器重啟之后數據還在。

       3)  服務器是單線程的,來自所有客戶端的所有命令都是串行執行的,因此不用擔心並發修改(串行操作當然還是有並發問題)的問題,編程模型簡單;

       4)  支持消息訂閱/通知機制,可以用作消息隊列;

       5)  Key、Value 最大長度允許 512M; 

     redis 的缺點: 

1)  Redis 是單線程的,因此單個 Redis 實例只能使用一個 CPU 核,不能充分發揮服務器的性能。可以在一台服務器上運行多個 Redis 實例,不同實例監聽不同端口,再互相組成集群。

2)  做緩存性能不如 Memcached; 

    Memcached 的優點:
              1) 多線程,可以充分利用 CPU 多核的性能; 2) 做緩存性能最高;

    Memcached 的缺點: 

       1)  只能保存鍵值對數據,鍵值對只能是字符串,如果有對象數據只能自己序列化成 json 字符串;

       2)  數據保存在內存中,重啟后會丟失;

       3)  Key 最大長度 255 個字符,Value 最長 1M。 

redis 命令行管理客戶端:
1)直接啟動 redis 安裝目錄下的 redis-cli 即可。不用管惡心的自動提示。 執行 set name yzk,就是設置鍵值對 name=yzk

執行 get name 就是查找名字是 name 的值;

keys *是查找所有的 key

key *n*是查找所有名字中含有 n 的 key

2) 和 Redis 一樣,Redis 也是不同系統放到 Redis 中的數據都是不隔離的,因此設定 Key 的 時候也要選擇好 Key。

3) Redis 服務器默認建了 16 個數據庫,Redis 的想法是讓大家把不同系統的數據放到不同 的數據庫中。但是建議大家不要這樣用,因為 Redis 是單線程的,不同業務都放到同一個 Redis 實例的話效率就不高,建議放到不同的實例中。因此盡量只用默認的 db0 數據庫。

命令行下可以用 select 0、select 1 這樣的指令切換數據庫,最高為 15。試試在不同數據 庫下新建、查詢數據。

35、用過負載均衡嗎

36、大數據處理

37、數據庫表數據量特別大時,如何優化查詢,提高速度?

38、數據庫中如何循環讀取數據庫表中的記錄?

      游標

39、數據庫中刪除重復數據

40、Session有什么缺點,微軟如何改進

   這是道筆試題,我們知道IIS會回收資源,所以可能會導致Session失效

41、有沒有用過消息隊列

     RabbitMQ

42、設計一個老鼠、貓和主人的程序,要求可擴展性強,老鼠的叫聲驚動貓和主人

    真無趣的一道題,用事件

43、Vue權限管理,如何控制界面的顯示

44、WCF的部署方式

     一般在IIS上,還有人部署在Window服務上

45、簡介應用程序池

46、冒泡算法

      c#寫一個,雙層循環

47、簡述應用程序域

48、數據庫設計三范式

49、SQL 事務的隔離級別有哪幾個?

     sql 事務隔離級別有四種分種為:

     一 Read Uncommitted(未提交讀)

     二 Read Committed(提交讀)

     三 Repeated Read(可重復讀)

      四 Serializable(序列)

      資料鏈接:https://www.cnblogs.com/wjwj/p/10719849.html

50、IQueryable和IEnumberable and IList與List區別      

 基本概念:
IEnumerable:使用的是LINQ to Object方式,它會將AsEnumerable()時對應的所有記錄都先加載到內存,然后在此基礎上再執行后來的Query
IQeurable(IQuerable<T>):不在內存加載持久數據,因為這家伙只是在組裝SQL,(延遲執行) 到你要使用的時候,例如 list.Tolist() or list.Count()的時候,數據才從數據庫進行加載 (AsQueryable())。
IList(IList<T>):泛型接口是 ICollection 泛型接口的子代,作為所有泛型列表的基接口,在用途方面如果作為數據集合的載體這是莫有問題的,只是如果需要對集合做各種的操作,例如 排序 編輯 統計等等,它不行。
List <> :泛型類,它已經實現了IList <> 定義的那些方法,IList<T> list=new List<T>();只是想創建一個基於接口IList<Class1>的對象的實例,這個接口是由List<T>實現的。只是希望使用到IList<T>接口規定的功能而已抽象場景:
其實在我們之前沒有使用 ORM 的的很久很久以前,我們 在ADO.net 里面使用的 DataReader 和 DataAdapter or DataSet 和這幾個貨的基本原理都接近的,就是讀取數據的時候,一個必須獨占着數據庫的連接,而另一個就是先把數據庫的的局加載到了自己本地,然后再進行操作。
使用場景模擬:
//IList
IList users = res.ToList(); //此時已把users加載到內存,而每個user的關聯實體 
                               //UserInfos)未被加載,所以下一行代碼無法順利通過
var ss = users.Where(p => p.UserInfos.ID != 3); //此處報錯,因為P的UserInfos實體無法被加載  
// IQuerable的
IQueryable users = res.AsQueryable(); //users未被立即加載,關聯實體可通過“延遲加載”獲得
var ss = users.Where(p => p.UserInfos.ID != 3);//此處順利獲得對應的ss

  總結: 

基於性能和數據一致性這兩點,使用IQueryable時必須謹慎,而在大多數情況下我們應使用IList。 

1.當你打算馬上使用查詢后的結果(比如循環作邏輯處理或者填充到一個table/grid中), 並且你不介意該查詢即時被執行后的結果可以供調用者(Consummer)作后續查詢(比如這是一個"GetAll"的方法),或者你希望該查執行,使用ToList()

2.當你希望查詢后的結果可以供調用者(Consummer)作后續查詢(比如這是一個"GetAll"的方法),或者你希望該查詢延時執行,使用AsQueryable()

3.按照功能由低到高:List<T> IList<T> IQueryable<T> IEnumerable<T>

4.按照性能由低到高:IEnumerable<T> IQueryable<T> IList<T> List<T>

       參考鏈接:https://www.cnblogs.com/sunliyuan/p/5823419.html

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM