小結:
1. 靜態類【static class】
a. 不能被執行個體化,實值型別(如:結構)不能用static修飾,因為CLR總是允許實值型別可以被執行個體化。
b. 靜態類直接繼承自System.Object
c. 靜態類不能實現任何介面,因為介面中的方法是要通過介面的實作類別執行個體化後訪問的,而靜態類是不能執行個體化的
2. Constants【常量】
a. 在編譯期間賦值,隱式認為是static的,但是在聲明時不能用static修飾
b. 當我們的代碼中引用了一個const常量時,compiler會先在程式集的metadata中尋找該常量的聲明,然後提取它的值並將其值直接放進IL Code中,也就是說在Runtime時,不需要分配記憶體空間來存放常量的值,所以我們擷取不到常量的地址
3. Fields【域】
域就是一個資料成員,該成員可以持有一個實值型別的執行個體,也可以持有一個對參考型別的引用
關於域的readonly修飾符:
a. 在聲明readonly變數時,可以對其賦值也可以不賦值
b. 只能在建構函式裡修改其值,其他地方都不允許
c. 如果一個參考型別變數被readonly修飾,那麼這個變數將是不可變的,即不能用它再去引用一個新的對象,如:
public sealed class Test{
public static readonly char[] tt = new char[]{'A','B','C'};
}
如果:Test.tt = new char[]{'X','Y','Z'};//將tt又引用了一個新的對象,這是不允許的
4. 字串
a. 字串是不可變的,即字串在建立之後就再也不能改變,其中包括變長、變短或者修改其中的任何字元。
如:
if (str.ToUpperInvariant().Substring(10,21).EndsWith("EXE"))
{
...
}
----以上會產生兩個臨時的字串,ToUpperInvariant()會產生一個,Substring(10,21)會產生一個,原str中的內容是不變的
----基於此,要想高效的操作大量字串,就使用StringBuilder類
b. 字串留用
記憶體中可能存在同一個字串的多個執行個體,這會造成記憶體的浪費,因為字串是“不可變”的。如果只在記憶體中保留字元串的一個執行個體,那麼將顯著提高記憶體的利用率,需要引用字串的所有變數只需指向同一個字串對象。
如果應用程式經常對字串進行區分大小寫、序號式的比較,或者事Crowdsourced Security Testing道許多字串對象都具有相同的值,就可以利用CLR中的字串留用機制來顯著提高效能。CLR初始化時,它會建立一個內部雜湊表,在這個表中,key是字串,而value是對託管堆中的String對象的引用。雜湊表最開始是空的,String類提供了兩個方法以便訪問這個內部雜湊表:
public static string Intern(string str);
----擷取一個String,獲得它的雜湊碼,並在內部雜湊表中檢查是否有相匹配的。如果已經存在一個完全相同的字串,就返回對現有的String對象的一個引用,並不會再次建立一
個String對象。如果不存在,就會建立字串的副本,並將副本添加到內部雜湊表中,並返回對這個副本的一個引用。
public static string IsInterned(string str);
----擷取一個String,並在內部雜湊表中尋找它。如果雜湊表中有一個匹配的字串,就返回對留用字串對象的一個引用,如果沒有,則返回null,不會將字串添加到雜湊表中
5. Parse方法與TryParse方法
取Int32為例,在Int32類中的定義為:
public static int Parse(string s); //轉換不成功會拋出異常
public static bool TryParse(string s, out int result); //轉換成功返回true,不成功則返回false,不會拋出異常
6. 關於異常拋出的起始點
----CLR只會記住最近拋出異常的位置
a.
try{...} catch(Exception e) { ... throw e; //將捕獲到的異常再次拋出,CLR會重設異常的起始點,即把異常的起始點改成現在這裡 }
b.
try{...} catch(Exception e) { ... throw; //將捕獲到的異常再次拋出,CLR不會重設異常的起始點 }
7. 在使用lock, using, foreach語句時,C#編譯器會自動把其代碼放在try語句塊中,然後在finally語句塊中做些資源關閉操作,如:調用Dispose()方法