C#是微軟推出的一種基於.NET 框架和後來的.NET 的、物件導向的進階程式語言。C# 是一種由 C 和 C++ 衍生出來的物件導向的程式語言。它在繼承 C 和 C++ 強大功能的同時去掉了一些它們的複雜特性，使其成為 C 語言家族中的一種高效強大的程式語言。C# 以.NET 框架類別程式庫作為基礎，擁有類似 Visual Basic 的快速開發能力。C# 由安德斯・海爾斯伯格主持開發，微軟在 2000 年發布了這種語言，希望藉助這種語言來取代 Java。C# 已經成為 Ecma 國際和國際標準組織的標準規範。



命名

C# 的發音為「C sharp」，「#」讀作「sharp」（/ʃɑːp/），命名啟發於音樂上的音名「C♯」，在音樂中「C♯」表示 C 升半音，為比 C 高一點的音節，且「#」形似 4 個加號，微軟藉助這樣的命名，以表示 C# 在一些語言特性方面對 C++ 的提升的意思。

由於顯示器（標準字體、瀏覽器等）的技術限制，且大部分的鍵盤配置上不存在升記號（♯），所以井號（#）被用於此程式語言的名稱中，約定在 ECMA-334 C# 語言規範中。



設計目標

ECMA 標準列出的 C# 設計目標：


* C# 旨在設計成為一種「簡單、現代、通用」，以及物件導向的程式設計語言

* 此種語言的實現，應提供對於以下軟體工程要素的支援：強型別檢查、陣列維度檢查、未初始化的變數參照檢測、自動垃圾收集（Garbage Collection，指一種記憶體自動釋放技術）。軟體必須做到強大、持久，並具有較強程式開發的生產力。

* 此種語言為在分散式環境中的開發提供適用的組件開發應用。

* 為使程式設計師容易遷移到這種語言，原始碼的可移植性十分重要，尤其是對於那些已熟悉 C 和 C++ 的程式設計師而言。

* 對國際化的支援非常重要。

* C# 適合為獨立和嵌入式的系統編寫程式，從使用複雜作業系統的大型系統到特定應用的小型系統均適用。

* 雖然 C# 程式在儲存和操作能力需求方面具備經濟性，但此種語言在某些情況下並不能在效能和程式大小方面與 C 語言相抗衡。



歷史

原 Borland 公司的首席研發設計師安德斯・海爾斯伯格（Anders Hejlsberg）在微軟開發了 Visual J++ 1.0，很快的 Visual J++ 由 1.1 版本升級到 6.0 版。SUN 公司認為 Visual J++ 違反了 Java 開發平台的中立性，對微軟提出了訴訟。2000 年 6 月 26 日微軟在奧蘭多舉行的「職業開發人員技術大會」（PDC 2000）上，發表新的語言 C#。C# 語言取代了 Visual J++，語言本身深受 Visual Basic、Java、C 和 C++ 的影響。

版本



語言特性

相對於 C 和 C++，這個語言在許多方面進行了限制和增強：


* 指標（Pointer）只能用於不安全模式之中。大多數物件存取透過安全的參照實現，以避免無效的調用，並且有許多演算法用於檢查溢位，指標只能用於調用值類型，以及受垃圾收集控制的代管物件。

* 物件不能被顯式釋放，代替為當不存在被參照時透過垃圾回收器回收。

* 只允許單一繼承（single inheritance），但是一個類可以實現多個介面（interfaces）。

* C# 比 C++ 更加類型安全。預設的安全轉換是隱含轉換，例如由短整型轉換為長整型和從衍生類轉換為基本類。而介面布林數同整型，及枚舉型同整型不允許隱含轉換，非空指標（透過參照相似物件）同使用者定義類型的隱含轉換欄位被顯式的確定，不同於 C++ 的複製構造函式。

* 陣列宣告的語法不同（"int [] a = new int [5]" 而不是 "int a [5]"）。

* 枚舉位於其所在的命名空間中。

* C# 中沒有模版（Template），但是在 C# 2.0 中引入了泛型（Generic programming），並且支援一些 C++ 模版不支援的特性。比如泛型參數中的類型約束。另一方面，表達式不能像 C++ 模版中被用於類型參數。

* 屬性支援，使用類似存取成員的方式調用。

* 完整的反射支援。



C# 2.0 的特性

針對於.NET SDK 2.0（相對應於 ECMA-334 標準第三版），C# 的新特性有：

部分類

分部類別將類別的實現分在多個檔案中。該概念於 C# 中首次出現，除了能將一個類別的成員分開存放，還使 ASP.NET 中的代碼後置得以實現。代碼後置實現了 HTML 代碼和後台互動代碼的分離。

file1.cs:

file2.cs:

分部類別這個特性允許將一個類別的編寫工作分配給多個人，一人寫一個檔案，便於版本控制。它又可以隔離自動生成的代碼和人工書寫的代碼，例如設計表單應用程式時。

泛型

泛型，或參數化類型，是被 C# 支援的.NET 2.0 特性。不同於 C++ 模版，.NET 參數化類型是在執行時被實例化，而不是編譯時，因此它可以跨語言，而 C++ 模版卻不行。C# 泛型類在編譯時，先生成中間代碼 IL，通用類型符號 T 只是一個預留位置；在實例化類時，根據實際資料類型代替 T 並由即時編譯器（JIT）生成本地代碼，其中使用了實際的資料類型，等同於用實際類型寫的普通的類。

它支援的一些特性並不被 C++ 模版直接支援，比如約束泛型參數實現一個介面。另一方面，C# 不支援無類型的泛型參數。不像 Java 中的泛型，在 CLI 虛擬機器中，.NET generics 使用具化生成泛型參數，它允許最佳化和儲存類型資訊。

泛型類中，可以用 where 關鍵字對參數類型實現約束。例如：

上述表示 T 和 V 必須是 Stack 類或其衍生類別，T 必須繼承了 IComparable 介面、有無參建構函式、是參照類型；V 必須是值類型。

泛型不僅能作用在類上，也可單獨用在類的方法上，稱為「泛型方法」。

泛型類的靜態成員變數在相同封閉類間共享，不同的封閉類間不共享。

泛型類中的方法多載，參數類型 T 和 V 在執行時確定，不影響這個類通過編譯。C# 的泛型是在實例的方法被呼叫時檢查多載是否產生混淆，而不是在泛型類本身編譯時檢查。特別地，當一般方法與泛型方法具有相同的簽章時，會覆蓋泛型方法。

靜態類別

靜態類別它不能被實例化，並且只能有靜態成員。這同很多過程語言中的模組概念相類似。

迭代器

一種新形式的迭代器它提供了函式語言程式設計中的 generator，使用 `yield return`

類似於 Python 中使用的 `yield`

注意事項：


* foreach 迴圈時考慮執行緒安全性，不要試圖對被遍歷的集合進行 remove 和 add 等操作

* IEnumerable 介面是 LINQ 特性的核心介面。只有實現了 IEnumerable 介面的集合，才能執行相關的 LINQ 操作，比如 select,where 等

匿名方法

匿名方法類似於函式語言程式設計中的閉包。匿名方法是通過使用 delegate 關鍵字建立委託實例來聲明的。例如：

委託的協變和逆變

委託簽章的協變和逆變，

屬性存取器可以被單獨設定存取級別

例子：

可空類型

可空類型（跟個問號，如 `int? i = null;`）允許設定 `null` 給任何類類型。

?? 運算子

（`??`）：如果左運算數表達式的值不為空值時回傳該值，如果為空值則返回右運算數表達式的值。

主要用作將一個可空類型賦值給不可空類型的簡便語法



C# 3.0 的特性

C# 3.0 發布於 2007 年 10 月 17 日，是.NET Framework 3.5 的一部分，它的新特性靈感來自於函式語言程式設計語言，如：Haskell 和 ML，並廣泛地引入了 Language Integrated Query（LINQ）模式到通用語言運行庫中 e.

Linq

語言整合查詢（英語：Language Integrated Query，縮寫：LINQ）： 上下文相關關鍵字 "`from`, `where`, `select`" 可用於查詢 SQL、XML、集合等。這些識別碼在 LINQ 上下文中被作為關鍵字，但是它們的增加不會破壞原有的名為 `from`、`where` 或 `select` 的變數。

類型初始化器

可寫作：

集合初始化器

可寫作

假設 `MyList` 實現了 `System.Collections.IEnumerable` 且有一個 `Add` 方法 method

匿名類型

局部變數類型推斷

局部變數類型推斷：

等同於

它只是一個語法糖，這個特性被匿名類型聲明時所需要

Lambda 表達式

Lambda 表達式（無函式名稱的物件方法在程式語言中的表達語法）:

　
: 可寫作

編譯器翻譯 Lambda 表達式為強型別委託或強型別表達式樹。

注意事項：


* 如果只有一個參數，可以省略括號 ()，例如 item=>{Console.WriteLine ("只有一個參數 {0} 的 Lambda 表達式",item); };

* 如果只有一個返回值的語句，可以省略花括號 {}、return 關鍵字、分號，例如 item => {return item % 2 == 0;}; 覆寫成：item =>item %2 == 0;

* Lambda 表達式可以分配給 Func，Action 或 Predicate 委託。

自動化屬性

編譯器將自動生成私有變數和適當的 getter（get 存取器）和 setter（set 存取器），如：

擴充方法

擴充方法能夠使現有的類型添加方法，而無需建立心的衍生類型、重新編譯或以其它方式修改原始類型。

使用拓展方法，必須在一個非巢狀、非泛型的靜態類中定義一個靜態方法，方法第一個參數必須附加 this 關鍵字作為字首，第一個參數不能有其它修飾詞（如 ref 或者 out），這個方法將被編譯器添加到該 this 的類型中。

注意事項：


* 擴充方法只會增加編譯器的工作，但不會影響程式執行效能（用繼承的方式為一個類型增加特性反而會影響效能）

* 如果原來的類中有一個方法，跟擴充方法一樣，那麼擴充方法不會被呼叫，編譯器也不會提示

分部方法

允許碼產生器生成方法聲明作為擴充點，如果有人在另一個部分類實現了它才會被包含於原代碼編譯。

1. 分部方法（Partial methods）必須定義在分部類（partial classes）中
2. 定義分部方法需要用 partial 做修飾詞
3. 分部方法不一定總是有執行內容的，也就是說定義的方法可以一句操作語句都沒有
4. 分部方法返回值必須是 void
5. 分部方法可以是靜態（static）方法
6. 分部方法可以包含參數，參數可以包含以下修飾詞：this,ref,params
7. 分部方法必須是私有（private）方法

例子：



C# 4.0 的特性

dynamic 類型

C# 4.0 新增 dynamic 關鍵字，提供動態編程（dynamic programming），把既有的靜態物件標記為動態物件，類似 javascript, Python 或 Ruby。

dynamic 關鍵字標記的實例被處理成一個特殊包裝的 object 物件，取消了 CLI 的編譯時型別檢查，編譯時被假定支援任何操作，但如果並不實際支援則執行時報錯。

具名參數與可選參數

呼叫 OpenFile 時，順序可以完全顛倒：

與 COM 組件互動

在 C# 中打開一個 Word 檔案：

在 C# 中指定 Excel 的某一格文字：

泛型的協變和逆變

C# 4.0 支援協變和逆變，例如在泛型介面可以加上 in、out 修饰字。



C# 5.0 的特性

1. C# Evolution Matrix
2. Async Feature （補充： async 和 await 是一對語法糖，允許開發人員非常輕鬆的呼叫基於 TASK 的非同步編程）async-await 關鍵字並不會真的建立一個執行緒池任務，完成這個動作依賴於被呼叫方法中的函式。這一點在許多 C# 的中文教程中被忽略，導致許多學習的新手誤以為 await 關鍵字會直接建立一個新的執行緒池任務。
3. Caller Information



C# 6.0 的特性

1. 唯讀 Auto 屬性
2. Auto 屬性初始設定式
3. 使用靜態
4. Null - 條件運算子
5. 字串插值
6. 例外狀況篩選條件
7. nameof 運算式
8. Catch 和 Finally 區塊中的 Await
9. 索引初始設定式
10. 集合初始設定式的擴充方法
11. 改進的多載解析

表達式主體（Expression-bodied）用於類的方法和唯讀屬性



C# 7.0 的特性

out 變數

能夠直接宣告一個變數在它要傳入的地方，當成一個 out 的引數

棄元

元組 / 物件的解構：

使用 is/switch 的模式匹配：

對具有 out 參數的方法的呼叫：

作用域內獨立使用場景：

表達式主體（Expression-bodied）用於類的屬性、構造器、終端子、索引器



C# 7.1 的特性

1. async``Main 方法
2. default 常值運算式
3. 推斷的 tuple 項目名稱



C# 7.2 的特性

1. 具備實值型別的參考語意
2. 無後置具名引數
3. 數值常值中的前置底線
4. private protected 存取修飾詞



C# 8.0 的特性

1. 可空參照類型
2. await yield return 可非同步返回的迭代器
3. Index 索引類型和 Range 區間類型
4. 允許在聲明介面時為介面成員提供預設實現
5. 遞迴的模式匹配
6. 表達式形式的 Switch 關鍵字
7. 在編譯器可做類型推斷的情況下，允許進一步省略類型聲明



C# 9.0 的特性

新的「Record」類型

記錄類型， 是一種參照類型， 預設是不可變的。 記錄類型的相等判斷可以通過參照或者結構進行判斷的。


* 優點：記錄類型是輕量級的不可變類型，可以減少大量的代碼， 可以按照結構和參照進行比較；

* 缺點：需要實例化大量的物件；

「init」存取子

init 存取子表示該屬性所屬類型僅能在建構函式 (Constructor) 中或是屬性初始化式子中賦予其值，如果嘗試在其他地方設定該屬性的值，在編譯時便會遭編譯器阻止。

範例如下：在這個範例中，建立了一個 `Student` 類型，並且屬性 `StudentName` 與 `StudentID` 只能在初始化時賦予其值。

如果在此時撰寫以下程式碼：

編譯器便會無法編譯並且擲回錯誤。

而如果要建立學生名稱為「Test Name」，學生 ID 為「0001」的學生，則需要寫成：

或是

最上層語句或稱頂級語句

在以前的版本，開發者在撰寫最上層語句 (如 Program.cs) 程式碼時，需要包含完整的 namespace 與 class 架構，因此如果要撰寫 Hello World 程式時，程式碼就會是：

但是在 C# 9.0 之後，最上層語句的程式碼不需要包含 namespace 以及 class，可將其簡化為：

注意， 一個程式中， 只能有一個檔案使用頂級語句， 並且頂級語句必須位於命名空間或類型定義之前。

lambda 棄元參數

在 C# 9 之前，即便不使用的 Lambda 參數也需要給它命名。C# 9 支援棄元參數一方面簡化了命名，另一方面也節省了記憶體分配。更重要的是它使得編程的意圖更明確，讓人一看就知道這個參數是不用的，增強了代碼的可讀性和可維護性。

只能初始化的設定器

Init only setters，只能通過物件初始化進行賦值的屬性。

函式指標

使用 delegate\
* 可以聲明函式指標。

跳過本地初始化

原生整數類型

兩個新的整數類型 nint 和 nunit ， 依賴宿主機以及編譯設定。

協變返回類型

協變返回類型為重寫方法的返回類型提供了靈活性。覆蓋方法可以返回從被覆蓋的基礎方法的返回類型衍生的類型。

模組初始化代碼

ModuleInitializerAttribute 為組件 (assembly) 定義初始化代碼， 當初始化 / 載入時執行， 可以類比類的靜態建構函式， 但是是組件級別的。


* 必須是靜態的、無參數的、無返回值的方法；

* 不能是範式方法，也不能包含在範式類中；

* 不能是私有函式，必須是公開 (public) 或者內部 (internal) 的函式；

靜態 lambda 表達式

static 修飾詞添加到 lambda 表達式或匿名方法 。這將無法擷取局部變數或實例狀態，從而防止意外擷取其他變數。

分部方法擴充

移除了分部方法的下述限制：


* 必須具有 void 返回類型。

* 不能具有 out 參數。

* 不能具有任何可存取性（隱式 private ）。

初始化表達式的簡化

如果建立物件的類型已知時，可以在 new 表達式中省略該類型。

在本地函式上添加標記

GetEnumerator 擴充

可以為任意類型添加一個 GetEnumerator 擴充方法， 返回一個 IEnumerator 或者 IAsyncEnumerator 實例， 從而在 foreach 迴圈中使用。

模式匹配增強

Type patterns 類型匹配，判斷一個變數的類型

Relational patterns 關係匹配：

Conjunctive and patterns 邏輯合取匹配：

Disjunctive or patterns 邏輯析取匹配：

Negated not patterns 邏輯非匹配

Parenthesized patterns 帶括號的優先級匹配：



C# 10.0 的特性

record struct

解決了 record 只能給 class 而不能給 struct 用的問題：

sealed record ToString 方法

可以把 record 里的 ToString 方法標記成 sealed

struct 無參建構函式

無參建構函式使得 new struct () 和 default (struct) 的語意不一樣

用 with 建立新的匿名類型物件

這裡 y.A 將會是 3 。

全域的 using

可以給整個專案啟用 using，不需要每個檔案都寫一份。

檔案範圍的 namespace

以前寫 namespace 還得帶一層大括號。現在如果一個檔案里只有一個 namespace 的話，直接在檔案開頭寫：`namespace MyNamespace;`

常數字串插值

lambda 的改進

lambda 可以帶 attributes

指定返回值類型

此前 C# 的 lambda 返回值類型靠推導，C# 10 允許在參數列之前顯式指定 lambda 返回值類型：

```
f = int () => 4;
```

支援 ref 、in 、out 等修飾

```
f = ref int (ref int x) => ref x; // 返回一个参数的引用
```

頭等函式

函式可以隱式轉換到 delegate，於是函式上升為頭等函式 (first function)：

自然委託類型

lambda 可自動建立自然委託類型，於是不再需要寫出類型：

CallerArgumentExpression

使用 CallerArgumentExpression 這個 attribute，編譯器會自動填充呼叫參數的表達式字串，例如：

當你呼叫 Foo (4 + 5) 時，會輸出 4 + 5 = 9。這對測試框架極其有用

tuple 的混合定義和使用

於是 y 就變成 2 了，同時還建立了兩個變數 x 和 z，分別是 1 和 3 。

介面支援抽象靜態方法

.NET 6 中這個特性為 preview 特性。

泛型 attribute

在方法上指定 AsyncMethodBuilder

在方法上用 [AsyncMethodBuilder (...)]，來使用自己實現的 async method builder，代替內建的 Task 或者 ValueTask 的非同步方法構造器。有助於實現零開銷的非同步方法。

line 指示器支援行列和範圍

以前 #line 只能用來指定一個檔案中的某一行，現在可以指定行列和範圍：

巢狀屬性模式匹配改進

以前在匹配巢狀屬性的時候需要這麼寫：

```
if (a is { X: { Y: { Z: 4 } } }) { ... }
```

現在只需要簡單的：

```
if (a is { X.Y.Z: 4 }) { ... }
```

改進的字串插值

實現接近零開銷的字串插值。

Source Generator v2

包括強型別的代碼構建器，以及增量編譯的支援等



程式的執行

C# 通常不被編譯成為能夠直接在電腦上執行的二進位本地代碼。與 Java 類似，它被編譯成為中間代碼（Microsoft Intermediate Language），然後通過.NET Framework 的虛擬機器 —— 被稱為通用語言執行層 —— 執行。

所有的.Net 程式語言都被編譯成這種被稱為通用中間語言的中間代碼。因此雖然最終的程式在表面上仍然與傳統意義上的可執行檔都具有「.exe」的字尾名。如果電腦上沒有安裝.Net Framework，那麼這些程式會彈出對話方塊，要求使用者下載.net framework。

在程式執行時，.Net Framework 將中間代碼翻譯成為二進位機器碼，從而使它得到正確的執行。最終的二進位代碼被儲存在一個緩衝區（Buffer）中。所以一旦程式使用了相同的代碼，那麼將會呼叫緩衝區中的版本。這樣如果一個.Net 程式第二次被執行，那麼這種翻譯不需要進行第二次，速度明顯加快。



標準化

微軟公司已經向 ECMA 申請將 C# 作為一種標準。在 2001 年 12 月，ECMA 發布了 ECMA-334 C# 語言規範。C# 在 2003 年成為一個 ISO 標準（ISO/IEC 23270）。現在有一些獨立的實現正在進行，包括：


* 自由軟體基金會的 dotGNU Portable.NET（頁面存檔備份，存於網際網路檔案館）

* Mono（頁面存檔備份，存於網際網路檔案館）

* Baltie - C# IDE for children and young Baltie（頁面存檔備份，存於網際網路檔案館）



範例

C# 的 Hello World 程式

下面是一個在命令提示字元上輸出 Hello World 的小程式，這種程式通常作為開始學習程式語言的第一個步驟：



實現

微軟正在引領開源參考 C# 編譯器和工具集的開發。 第一個編譯器 Roslyn 編譯成中間語言（IL），第二個編譯器 RyuJIT， 是一個 JIT（即時）編譯器，它是動態的，進行動態最佳化並編譯將 IL 轉換為 CPU 前端的本機代碼。 RyuJIT 是開源的，用 C++ 編寫。 Roslyn 完全是用 受控代碼 (C#) 編寫的，已經開放並且功能以 API 的形式出現。因此，它使開發人員能夠建立重構和診斷工具。 官方實現的兩個分支是 .NET Framework（閉源，僅限 Windows）和 .NET Core（開源，跨平台）；它們最終融合為一個開源實現：.NET 5.0。 在 .NET Framework 4.6 中，新的 JIT 編譯器取代了前者。

其他 C# 編譯器（其中一些包括公共語言基礎結構和 .NET 類別程式庫的實現）：


* 微軟的轉軸專案（Rotor Project，目前稱為 Shared Source Common Language Infrastructure），提供了通用語言執行層（_Common Language Runtime_）的實作與 C# 編譯器。但是 Shared Source Common Language Infrastructure 在 2006 年的 2.0 版後就停止了。

* 由 Microsoft 贊助的 Mono 專案提供了 C# 編譯器，它提供了一個開源 C# 編譯器、一個完整的 CLI 開源實現，同時也接近百分之百地實作了.NET Framework 類別庫。而 Mono 後來衍伸出由微軟認可的第三方套件 Xamarin。

* Dot GNU 專案（現已停產）也提供了另一個自由版本的 C# 編譯器，也提供了.NET Framework 類別庫的實作。

遊戲引擎 Unity 使用 C# 作為其主要手稿語言。由於 Microsoft 捐贈了 24,000 美元， Godot 遊戲引擎實現了一個可選的 C# 模組。



參考文獻



外部連結


* （英文）C# Language Specification (MSDN)（頁面存檔備份，存於網際網路檔案館）

* （英文）ECMA-334 C# Language Specification (.pdf)

* （英文）ISO/IEC 23270:2003 C# Language Specification（頁面存檔備份，存於網際網路檔案館）

* （英文）Visual Studio Code（頁面存檔備份，存於網際網路檔案館）

* （英文）Download .NET（頁面存檔備份，存於網際網路檔案館）

* Visual C# .NET 入門 (MSDN)（頁面存檔備份，存於網際網路檔案館）

* MCS: Mono C# 編譯器（頁面存檔備份，存於網際網路檔案館）

* Visual Studio Community（頁面存檔備份，存於網際網路檔案館）

* Visual C# Logo（頁面存檔備份，存於網際網路檔案館）

* C# 教學（頁面存檔備份，存於網際網路檔案館）

* C# 教材目錄（頁面存檔備份，存於網際網路檔案館）