C#/.NET 基礎學習

初識C#

  C#是微軟公司發佈的面向對象的、運行於.NET Framework之上的高級程序設計語言。與Java有着明顯不同,借鑑Delphi的特點,與COM(組件對象模型)直接集成,是微軟公司 .NET windows網絡框架的主角。
  C#是一種語言,.net是一個平臺。C#不但可以開發基於.net的應用程序,也可以開發基於WinForm的程序。. net 是 Microsoft 的 XML Web 服務平臺,XML Web 服務能使應用程序在 Internet 上傳輸和共享數據。
  
 特點:  
  1. 強類型語言,安全穩定;
  2. 事件驅動、完全面向對象的可視化編程語言;
  3. 便捷的面向組件編程的支持;
  4. VB簡單的可視化操作和C++的高運行效率的結合;
  5. 託管代碼和垃圾回收 (garbage collection);


  // .NET ~ C# ~ ASP.NET
  C#是.net平臺下的一種開發語言,用於開發桌面應用程序
  asp.net是開發web程序的技術 
 .net是平臺,該平臺下包含很多技術如:asp.net  ado.net  winform  WCF

 .NET框架
 CLR:公共語言運行庫,Common Language Runtime,.NET框架的核心組件,在操作系統的頂層並在運行期調用基類庫(BCL, Base Class Library)管理程序的執行。
  · 內存管理機制
  · 垃圾回收機制GC (Garbage Collector)
  · JIT編譯器
 CTS:公共類型系統,Common Type System,重要特性是所有類型都繼承自公共的基類object。


基礎學習

 4個基礎命名空間

// .NET框架中的基礎類庫,用於實現一些基本的類。
using System; .NET應用程序中使用的大多數基本類型
using System.Collections.Generic; 處理集合的泛型類型
using Syatem.Text; 字符串處理和編碼相關的類型
using System.Linq; 提供支持使用語言集成查詢(LINQ)進行查詢的類和接口,用於對集合進行查詢

 基礎概念
0. 結構 - 類
 struct 是值類型,隱式密封的、不能被繼承,但可以實現接口。struct 成員默認是 public,有構造函數(實例、靜態),沒有析構函數,不允許字段初始化。
 class 是引用類型,單繼承,可實現接口。class 成員默認是 private。
  · 數據 成員:字段、常量;
  · 函數 成員:屬性、方法、事件、索引器、構造函數、析構函數、操作符;
1. 字段 - 屬性 - 索引
 字段 - private,屬性 - public
 屬性 是指定的一組2個匹配的、稱爲訪問器 (get 和 set) 的方法。屬性是函數成員,訪問器只能被隱式調用,執行代碼,但不爲數據存儲分配內存。公有屬性提供對私有字段的受控訪問。
 索引 是一組 get 和 set 訪問器,類似屬性,索引是函數成員;索引通常用於訪問多個數據成員,類似數組利用索引運算符;索引不能聲明爲 static。訪問器只能被隱式調用,可以重載,參數列表必須不同。
  · 索引沒有名稱,但 this 是必須的;
  · 參數列表中至少必須聲明一個參數;

  ReturnType this[參數列表] {
       get {...}
       set {...}
  }

2. 靜態構造函數 - (普通的)實例構造函數
 實例構造函數初始化類的每個新實例,static 構造函數初始化類層次的項目。static 構造函數不能訪問類的實例成員,通常用於初始化類的靜態字段,靜態構造函數被系統自動調用。靜態字段先於實例成員被初始化,類只能有一個 static 構造函數,不能帶參數、不能有訪問修飾符、也不能使用 this 訪問器。
  [1]. 構造函數中不能調用虛方法;
  [2]. ;
  [3]. ;
3. 繼承
 單繼承。
 a. 重載:同一個類內的函數,函數名相同、參數列表不同;
 b. 重寫(覆蓋):父子類之間的函數,簽名相同、返回類型相同;父類用 virtual 標識,子類用 override 標識;
 c. 隱藏:默認或通過 new 顯式隱藏。base.數據成員/函數名 顯式訪問被隱藏的成員。
     · 字段:名稱相同,類型相同; 
     · 函數:簽名相同(函數名、參數列表(個數、順序、類型、修飾符));
4. 抽象類 abstract - 接口 interface
 a. 抽象類可以給出某些成員的一些實現,接口不能包含成員實現;
 b. 抽象類的抽象成員可以被子類部分實現,接口的成員必須被實現類全部實現;
 c. 一個類只能繼承一個抽象類(類單繼承),但是可以實現多個接口;
 d. 類是對對象的抽象,抽象類是對類的抽象,接口是對行爲的抽象
 e. 從設計角度,抽象類和接口設計的思維過程不同(相反):
   抽象類 - 自底向上,接口 - 自頂向下;
  - 接口 -
 引用類型,接口可以繼承接口,類和結構可以實現接口。接口允許訪問修飾符 public、protected、internal、private,接口成員不允許訪問修飾符,默認 public static。接口聲明不能包含數據成員,只能包含 屬性、方法、事件、索引
 類 A 實現接口 IA,將類 A 的對象引用轉換爲接口 IA 的引用:
  a. 強制類型轉換:IA ia = (IA)objA;但是若類 A 未實現接口 IA,則拋出異常。
  b. as 運算符:IA ia = objA as IA;若類 A 未實現接口 IA,返回 null、不拋出異常。
 實現接口的類可以從它的基類繼承實現代碼。類實現 2 個接口,2 個接口包含同名方法,類的單一實現就可以滿足 2 個接口 或 顯式實現每一個接口。同時可以分別獲得每一個接口的獨立引用。
 
  接口正常實現:接口方法不包含實現代碼,實現在類級別的方法中;
  接口顯式實現:接口方法包含實現代碼,沒有類級別的方法;
  :接口的顯式實現成員只能被相應的接口引用訪問,需要強制轉換操作。
5. 密封類 - 抽象類 - 靜態類
 a. 密封類:sealed,只能被用作獨立的類,不能被繼承,可實例化; 
 b. 抽象類:abstract,只能被繼承,不可實例化;
 c. 靜態類:static,靜態類是密封的。不能被繼承,不可實例化;
6. 裝箱 - 拆箱
 a. 裝箱:隱式轉換,把值類型打包到Object引用類型的一個實例中;
 b. 拆箱:顯式轉換,從對象中提取值類型;
 implicit、explicit 和 is、as
 ·  implicit - 隱式轉換,explicit - 顯式轉換;
    public static implicit/explicit operator 目標類型(源類型 源類型變量)
 :用戶自定義轉換僅針對於類和結構。is-as 不能用於用戶自定義轉換。is-as 不能重載。
 ·is:檢查對象類型兼容性並判斷能否成功轉換,返回bool,不拋出異常;
    適應範圍:引用轉換、裝箱轉換、拆箱轉換,if(obj is Type) Type t = (Type)obj;
   as:類似強制轉換,檢查對象類型兼容性並返回轉換結果,不拋出異常,失敗時返回null;
    適應範圍:引用轉換、裝箱轉換,Type t = obj as Type; if(null !=t){…}
    true/成功:obj 是 Type 類型或者 obj 是 Type 類型的子類型;
   對於 is,CLR 對對象類型檢查了次:is操作首先檢查obj是否和Type類型兼容。若兼容,在if語句內執行轉換時CLR再檢查obj是否爲一個Type引用並轉換。對於 as,CLR 對對象類型檢查了次:as操作檢查兼容性並直接轉換,效率高、性能好。
 參考is - as 詳解
7. object sender - EventArgs e
 a. object sender:保存觸發事件的對象的引用,指向發送通知的對象;
 b. EventArgs e:EventArgs 是包含事件數據的類的基類,在事件觸發時傳遞數據,但是 EventArgs 不包含任何數據,所有的事件參數類都必須從 EventArgs 類派生;
8. 變體
 變體分爲 協變 - 抗變 兩種,針對引用類型:
 a. 協變:covariance,父=子,out,只能用作方法的返回值或屬性get的訪問器;
 b. 抗變:contravariance,子=父,in,只能用作方法的參數;
9. 可空類型 ? - 空接合運算符 ??
 a. 可空類型允許創建普通值類型的變量並標註其有效性。可空類型是對普通值類型的 private 封裝,其問號語法是通過 System.Nullable<T> 利用泛型實現,與普通值類型可以相互轉換。不能創建引用類型的可空類型。2 個只讀屬性:
  - HasValue:bool 類型,標識是否有效; 
  - Value:變量值;(普通值類型的值、可空類型的值、null
 b. 空接合運算符允許在可空類型的變量爲 null 時返回一個給定值。 
10. 泛型
 類型是實例對象的模板,泛型類型是類型的模板。
 類型參數的約束用 where 子句列出:where 參數:constraint, constraint, …
  · 構造函數約束 new() 必須放在最後;
  · 主約束(class/struct)至多一個,且必須放在第一位; 
  · 接口約束可以有多個;
 只有 Type 類型或派生於 Type 類型的實參才能用於受約束的參數。 
 
委託 - 事件
 a. 委託 delegate:對函數的封裝,一種引用方法的類型 (引用類型),代表一類方法,具有相同參數列表和返回類型;
 b. 事件 event:委託的一種特殊情形,事件的類型是委託,事件是委託類型的變量,事件不是類型,事件是成員(變量)且被隱式自動初始化爲null;
  利用”+=”增加委託的實例/靜態方法,利用”-=”移除委託的實例/靜態方法。事件被觸發時,執行被委託的方法(調用委託來依次調用調用列表中的方法)。此處引用大話設計模式中的例子:
  public delegate void CatShoutEventHandler(object sender, EventArgs e);
  public event CatShoutEventHandler CatShout;
  委託是面向對象、類型安全的並且是可靠受控、安全的。當委託被調用時,它調用有序方法列表中的每一個方法。委託是恆定的,委託對象被創建後就不會再被改變。調用空委託會拋出異常,通過把委託和null比較判斷委託的調用列表是否爲空,進而判斷委託是否爲null。
 泛型委託
  public delegate TR FunHandler<T1, T2, TR>(T1 p1, T2 p2)
 匿名方法 -> Lambda表達式
  匿名方法,anonymous method,可以避免創建使用獨立的具名方法,允許在創建並初始化委託或爲委託增加方法時包含小段的內聯inline代碼。
    delegate(參數列表){語句塊};
  Lambda表達式避免冗餘信息、簡化匿名方法的語法。
 總結從 委託事件 到 觀察者模式
 
擴展方法
 允許向現有類型"添加"方法,而無需創建新的派生類型、重新編譯或以其他方式修改原始類型。類A需要新增一個方法,但類A是密封的或源代碼不可見,即不能修改類A,此時擴展方法允許在另一個類B中利用類A的公有可用成員實現類A需要新增的方法。
  · 擴展方法必須是靜態的,所在類也必須是靜態的;
  · 被擴展類型必須作爲第一個參數,必須用 this 修飾; 
 public static class ExtendMyClass {
   public static 返回類型 Function(this MyClass mc) {
      // 調用MyClass的公共成員實現新增方法
   }
 }
 調用:mc.Function();,如果沒有this,只能以ExtendMyClass.Function(mc);方式調用。
 擴展方法還可以結合泛型類,允許將(擴展)類中的靜態方法關聯到不同的泛型類上。擴展接口時,利用擴展方法比繼承接口(會強制要求實現接口下的所有方法)更方便。但是,擴展方法的優先級總是比被擴展類型本身中定義的同名實例方法低,且被擴展類型的子類不能繼承其父類型的擴展方法。
  · 將靜態方法轉成擴展方法,擴展方法本質上是靜態方法;
  · 編寫幫助類;
  · 爲 Linq 服務,實現鏈式編程;
 參考談擴展方法的理解C#擴展方法
    奇思妙想之擴展方法系列
 
枚舉 ~ 枚舉數 ~ 可枚舉類型
 枚舉 enum,值類型,成員是整數值常量,可以顯式爲其賦值初始化,但不能使用修飾符。枚舉可用於實現位標誌,注意添加 [Flags] 特性。
 可枚舉類型是實現了GetEnumerator()方法的類型,返回用於(讀取並返回)集合中數據項的枚舉數,枚舉數是可以依次返回集合中數據項的類對象。
 參考迭代器學習系列自定義類實現foreach
 [-1-]. IEnumerable / IEnumerator
  非泛型枚舉數和可枚舉類型,枚舉數類通常聲明爲類中的嵌套類。
  ·IEnumerator
   - Current:當前位置對應的數據項;
   - MoveNext():下移位置,初始位置爲-1;
   - Reset():復位;
  ·IEnumerable
   - IEnumerator GetEnumerator(): 
 [-2-]. IEnumerable<T> / IEnumerator<T>
  泛型枚舉數和可枚舉類型,類型安全。
 總結IEnumerable / IEnumerator 學習 - sqh  
   
 某些重要的關鍵字/修飾符/運算符
0. object 類
 C#中所有的類(型)都直接/間接繼承自System.Object類(型),值類型數據可以隱式轉換爲Object類型;object是引用類型,關鍵字object就是System.Object的別稱。
 靜態方法 
 [1]. public static bool Equals(object objA, object objB){}
   調用實例方法Equals(object obj),判斷是否相等;
 [2]. public static bool ReferenceEquals(object objA, object objB){}
   判斷兩個對象是否引用相等;
 實例方法
 [1]. public virtual bool Equals(object obj){}
   方法需要重寫用於實現根據值來判斷對象是否相等;
 [2]. public virtual int GetHashCode(){}:獲取對象的Hash值;
 [3]. public Type GetType(){}
   獲取當前實例的Type,查詢對象的元數據來確定對象的運行時類型;
 [4]. public virtual string ToString(){}:獲取當前實例的字符串信息,對象的字符串表達形式;
 受保護方法
 [1]. protected virtual void Finalize(){}
   類或派生類可以訪問,允許 Object 在“垃圾回收”機制回收 Object 之前嘗試釋放資源並執行其他清理操作;
 [2]. protected object MemberwiseClone(){}:創建當前實例的淺表副本;
1. partial
 a. 把類定義放在多個代碼文件中;
 b. 用於創建部分方法(定義聲明和方法實現),不能有訪問修飾符,返回值必須爲 void;
2. internal
 類和類成員的訪問修飾符,同一程序集權限。類默認是 internal,類成員默認是 private。
 protected internal:受保護的內部成員,同一程序集 or 子類權限。
 參考internal - 舉例參考
 嵌套類:嵌套是指類聲明的位置,而不是類實例的位置。
 嵌套類具有成員訪問級別,默認 private,可見性具體地:
  ·  嵌套類型的成員對封閉類型的成員具有完全訪問權限;
  ·  封閉類型的成員只能訪問嵌套類型的public和internal成員,不能訪問private和protected成員;
 嵌套類型的對象訪問封閉類型,需要維護封閉類型的引用。
3. using
 a. using 指令:命名空間指示符
 b. using 別名:類型別名指示符
  一個.cs文件引用了兩個不同的命名空間,但兩個空間都包括一個相同名字的類型,使用別名更簡潔。
  using aClass = NameSpaceA.MyClass;
  using bClass = NameSpaceB.MyClass;
 c. using語句:資源的包裝和管理 -> 隱式的 try…finally 塊
  定義一個範圍,在範圍結束時自動處理對象,自動調用這個類實例的 Dispose 方法。資源是一個實現 System.IDisposable 接口的類或結構。
4. 異常try…catch…finally
 結構化異常處理語法,標記出能處理異常的代碼和指令:
  ■  try:包含可能會拋出異常的代碼;
  ■  catch:拋出異常後要執行的代碼,catch塊可多個;
  ■  finally:始終一定會執行的代碼,釋放資源;
 try 塊是必須的,catch 和 finally 必須至少有一個。所有的異常類均派生於 System.Exception 類。
 異常嵌套的處理:如果異常出現在 Method2 方法內部,但是其 catch 塊沒有匹配的異常處理程序, 系統沿着調用棧向上搜索到 Method1,如果找到匹配的 catch 塊,系統先回到棧頂 Method2 處執行其 finally 塊,然後把 Method2 從調用棧中 pop(),最後執行 Method1 的相應 catch 塊和 finally 塊。

 public void Method2()                    public void Method1()     
 {                                         {
   try{                                      try{
     ...                                       Method2();
   }                                         }
   catch{...}                                catch{...}
   finally{...}                               finally{...}
 }                                         }

  ■  throw:顯式拋出異常;
   -throw Exception;異常拋出後,異常實例可以被 catch 塊捕獲。
   -throw;此種只能在 catch 塊內,捕獲後再重新拋出。
5. String、StringBuffer 與 StringBuilder
 String是字符串常量、定長,StringBuffer與StringBuilder是字符串變量、可變長、避免產生額外的臨時變量;StringBuffer線程安全,StringBuilder是非線程安全,三者的執行速度 StringBuilder > StringBuffer > String。具體區別詳見:
 參考 String - StringBuffer - StringBuilder.
 string - String
 String是.NET Framework中的類,string是C#中的類,C#的string映射爲.NET Framework的String;string是C#中的關鍵字,可以作爲String或System.String的別名;
6. const 與 readonly
 const只能在聲明語句中初始化,readonly可以在聲明語句或構造函數中初始化,const是編譯時常量、在內存中沒有存儲位置,readonly是運行時常量、在內存中有存儲位置;const是靜態的,readonly可以是靜態字段也可以是實例字段。
7. typeof 與 GetType
 typeof:一元運算符,返回作爲它的參數的任何類型的 System.Type 對象,不能重載。
 GetType:方法,可以調用 typeof 運算符,對任意類型的任意對象都有效。
8. var
 推斷類型,弱化類型的定義,可替代任何類型,但是 var 並不改變 C# 強類型性質。類似object,但object是引用類型,效率比var低。
 var 用於本地局部變量,不能用於字段,使用時必須初始化且不能再次賦類型不同的值;
 

 常用函數
1. Convert.ToInt32 - int.Parse(Int32.Parse)- int.TryParse - (int)
 a. Convert.ToInt32與int.Parse類似,Convert.ToInt32 內部調用了int.Parse,Convert.ToInt32 可以轉換的類型較多,int.Parse只能轉換數字類型的字符串;
 b. int.TryParse與int.Parse類似,但不會拋出異常,返回值爲bool以指示解析是否成功,從而可以免去添加異常處理代碼的麻煩,out參數爲轉換輸出值;
 此四者都可以解釋爲將類型轉換爲 int,eg:舉例參考.
 :所有預定義的簡單類型均包含靜態方法 Parse,將字符串解析爲相應的數據值。
2. Split
 String類的內置方法,分割函數,參數可以爲單個字符、多個字符、字符串。
 參考Split - 常用舉例參考Split的不同重載方法.
3. Trim
 String類的內置方法,用於去除字符串前後的指定字符,另外還有TrimStart()和TrimEnd()方法。
 參考Trim - 舉例參考.
4. DateTime
 · 與字符串string的轉換
  - DateTime.Parse(timeString);
  - Convert.ToDateTime(timeString);
  - if (DateTime.TryParse(timeString, out datetime)) {
     DateTime dm = datetime;
   }
 · DateTime
 
x. xxx


集合類數據存儲和檢索

命名空間:using System.Collections;
     using System.Collections.Generic;
ArrayList 對應的泛型集合是 List,與 HashTable 對應的泛型集合是 Dictionary
 - ArrayList:是Array的複雜版本,動態數組,實現了ICollection和IList接口,針對任意類型、任意長度,非類安全型的;
  聲明:ArrayList mAList = new ArrayList();
  具體地屬性方法類似List,此處不再贅述。 
 - HashTable:每個元素都是一個存儲在DictionaryEntry對象中的鍵值對。keyvalue鍵值對均爲object類型,支持任何類型的keyvalue鍵值對,非類安全型的;線程安全的;
  聲明:Hashtable ht = new Hashtable();
  遍歷哈希表元素:
   foreach(DictionaryEntry de in ht)
  哈希表排序:
   ArrayList KeysAList = new ArrayList(ht.Keys);
   KeyAList.Sort();
1. 泛型List
 聲明:List<T> mList = new List<T>();
 屬性方法:
  - mList.Count:對鏈表mList元素計數
  - mList.Add(T item):添加元素
  - mList.Insert(int pos, T item):指定位置插入元素
  - mList.AddRange(List list):鏈接2個List
  - mList.Contains(T item):測試List是否包含元素item
  - mList.Item(int idx):索引器,通過指定索引獲取或設置元素
  - mList.Remove(T item):刪除指定的元素
  - mList.RemoveAt(int pos):刪除指定位置的元素(推薦)
  - mList.RemoveRange(int b, int n):刪除從b開始的n個元素
  - mList.Clear():清空List
  - mList.Reverse():反轉List
  - mList.Sort():排序List
2. 泛型Dictionary
  在C#中,Dictionary提供快速的基於鍵值的元素查找。Dictionary<[key], [value]>,鍵必須唯一且不能爲空引用null,值若爲引用類型則可以爲空。
 聲明:Dictionary<T1, T2> mDict = new Dictionary<T1, T2>();
 屬性方法:
  - mDict.Count:對字典mDict元素計數
  - mDict.Add(T1 key, T2 value):添加元素(鍵, 值)對
  - mDict.ContainsKey(T1 key):字典是否包含鍵爲key的元素
  - mDict.ContainsValue(T2 value):字典是否包含值爲value的元素
  - mDict.Remove(T1 key):移除鍵爲key的元素
  - mDict.Clear():清空Dict
  - 遍歷字典元素
    1. By KeyValuePair
     foreach (KeyValuePair<T1, T2> kvp in mDict) 或 foreach(var kvp in mDict)
    2. By Key
     Dictionary<T1, T2>.KeyCollection keyCol = mDict.Keys;
     foreach (T1 key in keyCol)  或  foreach(T1 key in mDict.Keys) 
    3. By Value
     Dictionary<T1, T2>.ValueCollection valueCol = mDict.Values;
     foreach (T2 value in valueCol)  或  foreach(T2 value in mDict.Values)
  - mDict[key] = value:通過索引器讀寫鍵值對
  - mDict.TryGetValue(T1 key, out value_T2):獲取與指定的鍵相關聯的值。通過鍵取值,包括兩個參數,一個是要查詢的鍵,另一個是獲取的值,注意值前面使用out關鍵字。
  注:“判斷鍵存在”和“根據鍵取值”兩步轉化爲一步,鍵的哈希值只計算一次,效率高。
 以下三個集合類,可以進一步參考 Stack - Queue - SortedList.
3. SortedList
 System.Collections.SortedList類表示按鍵排序的鍵/值對的集合,可以按鍵或索引訪問,是數組和哈希表的組合。
 聲明:SortedList sList = new SortedList();
 遍歷排序列表元素:
  foreach(DictionaryEntry de in sList)
 - 泛型SortedList
 
4. 堆棧 Stack
 System.Collections.Stack類表示對象的LIFO集合,處理順序多變。
 聲明:Stack st = new Stack();
 屬性方法:
  - st.Peek:取棧頂元素,但不將其移除;
  - st.Push(object obj):棧頂入棧;
  - st.Pop():出棧,移除並返回位於Stack棧頂處的對象;
 - 泛型Stack

5. 隊列 Queue
 System.Collections.Queue類表示對象的FIFO集合,順序處理集合中的對象。
 聲明:Queue qu = new Queue();
 屬性方法:
  - qu.Peek:取隊首元素,但不將其移除;
  - qu.Enqueue(object obj):隊尾入隊;
  - qu.Dequeue():出隊,移除並返回位於Queue開始處的對象;
 - 泛型Queue
 
 當有多個線程併發訪問集合時,應該用System.Collections.Concurrent命名空間代替上述命名空間中的對應類型,線程安全的集合類可由多個線程同時訪問:
 - ConcurrentDictionary
 
 - ConcurrentQueue
 

參考鏈接

[1]. 經典.Net面試題
[2]. .Net面試題系列 0-9

發佈了60 篇原創文章 · 獲贊 21 · 訪問量 5萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章