面試出現頻率:基本上確定出現css
重要程度:10/10,身家性命般重要。一般這也是各類招聘工做的第一個要求,即「熟悉C#」的一部分。連這部分都不清楚的人,能夠說根本不知道本身天天都在幹什麼。咱們每天使用C#寫程序,但若是連C#基礎的東西都不懂,怎麼證實你「熟悉C#」呢?怎麼讓人覺的你對C#有興趣呢?html
不少人去面試一發現面試官開始問基礎題,就十分不爽,被淘汰了以後,還寫博客說面試官垃圾,怎麼不問問項目經歷,哥但是作過很多項目的。卻不知,面試官知道你作過那些項目,但一般來講,若是那些項目不是牛逼透頂的級別(例如你參與了淘寶雙11致使數據庫併發問題的改進,或者AlphaGo的算法設計),或者正好是面試官所在公司須要的類型,則這並非什麼很厲害的事情,是個程序員就有幾個項目在身,「作過很多項目」的牛逼程度,差很少等於「活過20幾年」(我都活了20幾年了,我牛逼麼?)。每一個人都有的東西,有什麼好問的,問你了你能肯定你能答得比別人好麼?可是若是你不能答出什麼是裝箱,你會引起面試官如下的猜測:前端
最重要的是,若是你裝箱都不知道,面試官後面的N個連環問題立刻胎死腹中,他可能會一臉尷尬,由於「我只是用這個問題當破冰的啊,你怎麼已經倒地了」,甚至不知道該問你啥,你才知道。C#話題就此終結,和藹點的面試官,可能會問問你在簡歷上寫的其餘東西。但不管如何,你的價值已經狂跌了不止一個檔次。jquery
在老外看來,這部份內容更爲重要。不少老外,尤爲是從優越國家來的那幫人,認爲人找工做確定是爲了興趣,錢只不過是順帶得到的。他們根本不知道這世界上還有人會考慮一個自身毫無興趣,僅僅是工資高的工做。若是他們發現,你連裝箱都不知道是什麼,他們會以爲你不熟悉C#,對C#一點興趣都沒有,直接把你請出面試室,儘管你可能已經用C#寫了幾十個工程,手下可能已經有了幾個小弟。也許你會央求面試官轉換一個話題,例如問問設計模式,但我的認爲,基礎有問題的人,即便知道設計模式,作過不少項目,他寫出來的asp.net代碼多是一坨屎的概率要遠遠高於基礎沒問題,但徹底不懂asp.net的人。這也是爲何不少老外的C#書籍前幾章的內容好像都是些「毫無心義的」,「莫名其妙的」東西。CLR via C#更是其中的戰鬥機,你徹底不用看這本書,也能寫出一個後臺用asp.net MVC,前端html+css+jquery的ERP系統出來,先後端使用ajax通信,後端連數據庫,用sql查數據,作CRUD。可是你不能憑藉這個找到一個工資高的工做,由於會幹這個的人實在是太多了,以致於不夠值錢。若是你以爲這已是了不得的成就,那麼你這一輩子也就停留在這裏了。若是你還想掙得更多,那麼你就得會別人不會或者嗤之以鼻的東西。程序員
而工資高的工做,或對性能有很高的要求,或若是你寫的代碼太差,那真的會出大事,因此不能請基礎差的人(固然好公司會有層層環境把關,但若是你的代碼老出問題,你的水平弱於公司平均水平太多,他們也不會請你)。小公司尤爲是外包,或者沒什麼名氣的公司寫的產品,自己也沒有多少人用,崩潰了不會死人,因此代碼垃圾一點無妨,只要能按時完成任務就得。面試
不少人反感基礎題,一個很大的緣由在於,問問題的人不會問。若是問法是考定義,好比問「值類型與引用類型有何區別?」 這種問題的答案一查都找獲得,也沒有什麼意義。較好的問法是,把概念問題融入到情景之中,或者構造一個連環問題。例如我遇到過的一個問題:你什麼時候會考慮使用一個結構體?我以爲一個不錯的答案是」當這個對象全部的屬性都是值類型時,例如刻畫N維座標系上的一個點」。若是面試者是如此做答,那麼你能夠繼續問「能夠用類型麼?「這個時候,實際上仍是在問你值類型與引用類型有何區別,但相比直接問就天然不少。這個問題並非概念題,而是天天工做都會要遇到的。你總須要創建自定義的對象吧,那你就得從類型,結構,接口...中選擇一個。ajax
須要理解的程度:熟悉值類型和引用類型的區別,以及它們之間是能夠轉換的(雖然這種轉換基本上是必定要避免的)。對棧和堆上內存的活動有着清醒的認識。算法
參考資料:sql
公共類型系統(CTS)是用來描述IL的,它規定了IL能作什麼,能定義什麼樣的變量,類中容許擁有什麼成員等等。若是你寫了一個不遵循CTS的語言(以及一個編譯器),那麼你的語言不能被當作是.NET平臺的語言,編譯出來的中間代碼(若是有的話)不是IL。CTS和IL是全部.NET語言的爸爸。數據庫
C#的數據類型能夠分爲值類型和引用類型。這是由於,CTS爸爸規定數據類型能夠分爲值類型和引用類型,並且C#實現了這部分功能。你能夠開發一個遵循CTS的語言,但不實現任何值類型。
全部類型都從System.Object派生,接口是一個特例。下面是一些主要的System.Object提供的方法:
CLR要求全部對象都用new操做符來建立。對於值類型,你能夠直接賦值,這至關於隱式的調用了new操做符。new操做符所作的事情有:
例以下面的代碼中,C#首先將a初始化爲5,而後再修改爲10。
1 class SomeType 2 { 3 private static int a = 5; 4 5 static SomeType() 6 { 7 a = 10; 8 } 9 }
CLR via C#上的這個例子可讓咱們透徹理解前一小節的內容以及內存中的各類活動。假設咱們有以下的定義。
若是代碼以下圖左下角所示,則開始執行的時刻,內存中的狀況以下圖:
當CLR掃描完M3方法以後,發現有兩個引用類型Employee和Manager,故計算這兩個類型及其全部基類型中定義的全部實例字段須要的字節數,在堆上創建兩個類型對象,它們的構造相同:類型對象指針(TypeHandle),同步塊索引,靜態字段集合與方法表(儲存了全部的方法)。
由於程序還沒運行到第二行,因此棧上暫時尚未那個整型對象year。當運行完前2行時,棧中多了2個成員。一個Employee對象e被建立,但其沒有指向任何東西。
但運行完第三行後,new關鍵字在堆上新建了一個實例,並返回這個引用,使得e指向一個Manager實例,這個實例的類型對象指針指向Manager類型對象。注意,一個類型不管有多少個實例,它們在堆中的對象都指向一個類型對象。另外須要關注的是,靜態字段在類型對象中,而類型對象是惟一的,因此全部該類型的實例都指向一個類型對象,意味着一個實例更改了靜態字段的值,全部其餘實例都會受影響。
第四句調用了靜態方法lookup。假設結果代表,Joe是公司的一名經理,則該方法將返回一個Manager對象。此時堆中將再次建立一個新的Manager對象,而e將會被指向這個新的對象。這個新的對象將會被初始化,Joe將做爲其初始化的信息的一部分(再也不是默認的值,例如0或者Null)。
注意此時第一個Manager對象將會變成垃圾,等待垃圾回收器的回收。兩個Manager對象指向一個Manager類型對象。
第五句代碼將調用一個Employee類型的方法,假設返回5,那麼year的值將變成5。
最後一句是一個虛方法,執行虛方法時,和實方法不一樣。咱們要看虛方法有沒有被人重寫,還要根據調用虛方法的對象(e)肯定使用父類中的方法,仍是子類中重寫的方法。根據上圖發現,e實際上是一個指向Manager對象的東西,因而,咱們執行在Manager類中重寫的那個方法。
注意若是在第四句中,Joe僅僅是一個Employee而不是Manager的話,那麼堆中將不會有第二個Manager對象,而取而代之爲一個新的Employee對象。最後一句也會執行在Employee中的方法,而不是Manager中的方法。
一個類型不管有多少個實例,它們在堆中的對象的類型對象指針都指向同一個類型對象。之因此只有一個類型對象,是由於不須要有多於一個(全部相同類型的定義都相同,都有相同的方法表)。因此,類型對象是儲存類型靜態成員最恰當的地方。類型對象由CLR在堆中的一個特殊地方(加載堆)建立(在第一次使用前),其中包括了類型的靜態字段和方法表。建立完以後,就不會改變,經過這個事實,能夠驗證靜態字段的全局(被全部同類型的實例共享)性。
類型對象是反射的重要操做對象。若是你要處理一個謎之對象,你不知道他有什麼方法,那麼你只能經過訪問它的類型對象,你才知道這個謎通常的對象究竟包括什麼方法。而後你就能夠調用這些方法。GetType方法會返回對象指向的類型對象(包括靜態成員和方法表)。
加載堆不受GC控制,因此靜態字段和屬性也不受GC控制。
1 int a = 123; // 建立int類型實例a 2 int b = 20; // 建立int類型實例b 3 var atype = a.GetType(); // 獲取對象實例a的類型Type 4 var btype = b.GetType(); // 獲取對象實例b的類型Type 5 Console.WriteLine(System.Object.Equals(atype,btype)); //輸出:True 6 Console.WriteLine(System.Object.ReferenceEquals(atype, btype)); //輸出:True
這意味着,內存中只有一個Int32類型對象,不然ReferenceEquals是不可能輸出True的。
注意,類型對象也有類型對象指針,這是由於類型對象本質上也是對象。全部的類型對象的「類型對象指針」都指向System.Type類型對象。特別的,System.Type類型對象自己也是一個對象,內部的「類型對象指針」指向它本身。
屬於BCL而非任何某個語言的類型叫作基元類型(Primitive Type)。你能夠在mscorlib.dll中找到它們。例如:
IL 類型 C# 關鍵字 VB.NET關鍵字
System.Byte byte Byte
Sytem.Int16 short Short
System.Int64 int Integer
特別的,string映射到基元類型String。因此它們並無任何區別。
C#的數據類型能夠分爲值類型和引用類型,它們的區別主要有:
A a = new A();
A a2 = a;
此時在堆中只有一個A的實例,而a和a2都指向它。因此若是咱們更改了a中某個成員的值,a2中相應的成員也會更改。(這稱爲淺複製,與之對應的深複製則是要逐一複製對象全部成員的值,C#沒有深複製的方法,要本身實現)值類型則徹底不一樣,複製值類型將進行逐字段的複製,而沒有指針參與。因此值類型是相互獨立的。更改其中一個對另一個不會有影響。
類和結構是C#兩個最主要的研究對象:
當試圖表現例如點(X維座標上的),形狀(長,寬,面積等屬性)等所有爲值類型組成的對象時,考慮使用結構體。例如,若是聲明一個 1000 個 Point 對象組成的數組,爲了引用每一個對象,則需分配更多內存(堆上的1000個實例);這種狀況下,使用結構能夠節約資源。當數組不用時,若是是使用結構體,則1000個對象將立刻銷燬,若是是使用類,則還要等GC,無形中提高了GC壓力。
Console是一個類。
Int32是一個結構。其只含有兩個常數的,Int32類型的字段(最小值和最大值),和若干方法。
這二者均位於基礎類庫mscorlib中。
類型的實例構造函數不能被繼承。它負責將類型的實例字段初始化。對於靜態字段,由靜態構造函數負責。
若是類型沒有定義任何構造函數,則編譯器將定義一個沒有參數的構造函數。其會簡單地調用基類的無參構造函數。特別的,因爲System.Object沒有任何實例字段,因此它的構造函數什麼也不作。
能夠聲明多個不一樣的構造函數。能夠利用this關鍵字來調用其它構造函數。
結構體的構造函數必須初始化它的全部成員。結構的構造函數不會被自動調用。
不能顯式地爲結構聲明無參數的構造函數。
靜態構造函數是一個特殊的構造函數,它會在這個類型第一次被實例化或引用任何靜態成員以前,CLR在堆上建立類型對象時執行,它具備如下特色:
若是咱們不瞭解堆上的內存分配方式,對靜態構造函數的理解會十分困難。爲何是在建立第一個實例以前?爲何不能直接調用?爲何不能有參數?咱們徹底沒法理解,只能經過死記硬背的方式記住這些性質。但若是你知道靜態成員在類型對象中,並不存在於任何的實例中,可能你就會理解這些性質。
當咱們清楚的瞭解了類型對象以及CLR對類型對象的處理方式時,理解靜態構造函數以及類型的靜態成員就顯得十分天然了。當建立第一個實例以前,堆上沒有類型對象,因此要調用靜態構造函數,當引用靜態成員以前,堆上也沒有類型對象,而靜態成員屬於類型對象,因此也要調用靜態構造函數,這兩種狀況的最終結果,都是堆上最終出現了一個類型對象。由於類型對象只須要創建一次,因此這個靜態構造函數也只能運行一次。
爲何靜態構造函數既沒有訪問修飾符,也沒有參數?這是由於靜態構造函數只負責初始化靜態成員,只負責維護類型對象,它和類型的實例對象沒有關係,因此你加入任何參數(你試圖爲非靜態的字段或屬性賦值?這是不可能的,由於根本就沒有實例)都是沒有意義的。
沒法直接調用靜態構造函數:如今顯然十分容易理解了,由於類型對象只能有一個,若是能夠隨便被調用,則可能會創造出好幾個類型對象,破壞靜態字段的全局性。CLR也選擇不把控制權交給用戶。