C 是微軟推出的一種基於NET 框架和後來的NET 的、面向物件的高階程式語言。C 衍伸自 C 和 C，繼承了 C 和 C 的強大功能，同時去掉了一些複雜特性，使其成為 C 語言家族中高效強大的程式語言。C 以NET 框架類庫作為基礎，擁有類似 Visual Basic 的快速開發能力。C 由安德斯海爾斯伯格主持開發，微軟在 2000 年釋出了這種語言，希望藉助這種語言來取代 Java。C 已經成為 Ecma 國際和國際標準組織的標準規範。 設計目標 ECMA 標準列出的 C 設計目標： C 旨在設計成為一種「簡單、現代、通用」，以及面向物件的程式設計語言 此種語言的實現，應提供對於以下軟體工程要素的支援：強型別檢查、陣列維度檢查、未初始化的變數引用檢測、自動垃圾收集（Garbage Collection，指一種記憶體自動釋放技術）。軟體必須做到強大、持久，並具有較強 zhhans 的程式設計；zhhant 程式開發的 生產力。 此種語言為在 zhhans 分散式；zhhant 分散式 環境中的開發提供適用的元件開發應用。 為使程式設計師容易遷移到這種語言，原始碼的可移植性十分重要，尤其是對於那些已熟悉 C 和 C 的程式設計師而言。 對國際化的支援非常重要。 C 適合為獨立和嵌入式的系統編寫程式，從使用複雜作業系統的大型系統到特定應用的小型系統均適用。 歷史 原 Borland 公司的首席研發設計師安德斯海爾斯伯格（Anders Hejlsberg）在微軟開發了 Visual J 10，很快的 Visual J 由 11 版本升級到 60 版。SUN 公司認為 Visual J 違反了 Java 開發平臺的中立性，對微軟提出了訴訟。2000 年 6 月 26 日微軟在奧蘭多舉行的 職業開發人員技術大會（PDC 2000）上，發表新的語言 C。C 語言取代了 Visual J，語言本身深受 Visual Basic、Java、C 和 C 的影響。 版本 版本 語言規格 語言規格 語言規格 日期 NET 框架版本 Visual Studio 的版本 版本 ECMA ISOIEC Microsoft 日期 NET 框架版本 Visual Studio 的版本 C 10 2002 年 12 月 2003 年 4 月 2002 年 1 月 2002 年 1 月 NET Framework 10 Visual Studio NET 2002 C 11C 12 2002 年 12 月 2003 年 4 月 2003 年 10 月 2003 年 4 月 Visual Studio NET 2003 2006 年 6 月 2006 年 9 月 2005 年 9 月 2005 年 11 月 NET Framework 20 Visual Studio 2005 colspan2 rowspan2 2007 年 8 月 2007 年 11 月 NET Framework 20 Except LINQ NET Framework 30 Except LINQ NET Framework 35 Visual Studio 2008Visual Studio 2010 2010 年 4 月 2010 年 4 月 NET Framework 4 Visual Studio 2010 C 50 2017 年 12 月 2018 年 12 月 2013 年 6 月 2012 年 8 月 NET Framework 45 Visual Studio 2012Visual Studio 2013 C 60 colspan2 rowspan2 草案 2015 年 7 月 20160627 NET Framework 46NET Core 10 Visual Studio 2015 C 70 建議草案 2017 年 3 月 NET Framework 462 Visual Studio 2017 C 71 建議草案 2017 年 8 月 20160814 NET Core 20 Visual Studio 2017 version 153 C 72 建議草案 2017 年 11 月 NET Framework 471 Visual Studio 2017 version 155 C 73 建議草案 2018 年 5 月 2018053020181204 NET Framework 472NET Core 21NET Core 22 Visual Studio 2017 version 157 C 8 建議草案 2019 年 9 月 2019092320191203 NET Framework 48NET Core 30NET Core 31 Visual Studio 2019 version 163 C 9 建議草案 2020 年 11 月 NET 5 Visual Studio 2019 version 168 C 10 建議草案 2021 年 11 月 NET 6 Visual Studio 2022 version 170 C 11 建議草案 2022 年 11 月 NET 7 Visual Studio 2022 version 174 C 12 建議草案 2023 年 11 月 NET 8 Visual Studio 2022 version 178 C 13 建議草案 2024 年 9 月 NET 9 Visual Studio 2022 version 1712 語言特性 相對於 C 和 C，這個語言在許多方面進行了限制和增強： zhhans 指標；zhhant 指標（Pointer）只能用於不安全模式之中。大多數物件訪問透過安全的引用實現，以避免無效的呼叫，並且有許多 zhhans 演算法；zhhant 演演算法 用於 zhhans 驗證；zhhant 檢查zhhans 溢位；zhhant 溢位，zhhans 指標；zhhant 指標 只能用於呼叫值型別，以及受垃圾收集控制的託管物件。 物件不能被顯式釋放，代替為當不存在被引用時透過垃圾回收器回收。 只允許單一繼承（single inheritance），但是一個類可以實現多個介面（interfaces）。 C 比 C 更加型別安全。zhhans 預設；zhhant 預設 的安全轉換是隱含轉換，例如由短整型轉換為長整型和從衍生類轉換為基本類。而介面 zhhans 布林型；zhhant 布林數 同整型，及列舉型同整型不允許隱含轉換，非空 zhhans 指標；zhhant 指標（透過引用相似物件）同用戶定義型別的隱含轉換欄位被顯式的確定，不同於 C 的複製建構函式。 陣列 zhhans 宣告；zhhant 宣告的 語法不同（int a new int 5 而不是 int a 5）。 列舉位於其所在的名稱空間中。 C 中沒有模版（Template），但是在 C 20 中引入了泛型（Generic programming），並且支援一些 C 模版不支援的特性。比如泛型引數中的型別約束。另一方面，表示式不能像 C 模版中被用於型別引數。 屬性支援，使用類似訪問成員的方式呼叫。 完整的反射支援。 C 20 的特性 針對於NET SDK 20（相對應於 ECMA334 標準第三版），C 的新特性有： 部分類 分部類別將類別的實現分在多個檔案中。該概念於 C 中首次出現，除了能將一個類別的成員分開存放，還使 ASPNET 中的程式碼後置得以實現。程式碼後置實現了 HTML 程式碼和後臺互動程式碼的分離。 file1cs public partial class MyClass1 public void MyMethod1 implementation file2cs public partial class MyClass1 public void MyMethod2 implementation 分部類別這個特性允許將一個類別的編寫工作分配給多個人，一人寫一個檔案，便於版本控制。它又可以隔離自動生成的程式碼和人工書寫的程式碼，例如設計窗體應用程式時。 泛型 泛型，或引數化型別，是被 C 支援的NET 20 特性。不同於 C 模版，NET 引數化型別是在執行時被例項化，而不是編譯時，因此它可以跨語言，而 C 模版卻不行。C 泛型類在編譯時，先生成中間程式碼 IL，通用型別符號 T 只是一個佔位符；在例項化類時，根據實際資料型別代替 T 並由即時編譯器（JIT）生成原生代碼，其中使用了實際的資料型別，等同於用實際型別寫的普通的類。 它支援的一些特性並不被 C 模版直接支援，比如約束泛型引數實現一個介面。另一方面，C 不支援無型別的泛型引數。不像 Java 中的泛型，在 CLI 虛擬機器中，NET generics 使用具化生成泛型引數，它允許最佳化和儲存型別資訊。 泛型類中，可以用 where 關鍵字對引數型別實現約束。例如： class NodeT V where T Stack IComparable new class where V Stack struct 上述表示 T 和 V 必須是 Stack 類或其派生類，T 必須繼承了 IComparable 介面、有無參建構函式、是引用型別；V 必須是值型別。 泛型不僅能作用在類上，也可單獨用在類的方法上，稱為 泛型方法。 泛型類的靜態成員變數在相同封閉類間共享，不同的封閉類間不共享。 泛型類中的方法過載，引數型別 T 和 V 在執行時確定，不影響這個類透過編譯。C 的泛型是在例項的方法被呼叫時檢查過載是否產生混淆，而不是在泛型類本身編譯時檢查。特別地，當一般方法與泛型方法具有相同的簽名時，會覆蓋泛型方法。 靜態類別 靜態類別它不能被例項化，並且只能有靜態成員。這同很多過程語言中的模組概念相類似。 迭代器 一種新形式的迭代器它提供了函數語言程式設計中的 generator，使用 yield return 類似於 Python 中使用的 yield Method that takes an iterable input possibly an array and returns all even numbers public static IEnumerableint GetEven IEnumerableint numbers foreach int i in numbers if i 2 0 yield return i 注意事項： foreach 迴圈時考慮執行緒安全性，不要試圖對被遍歷的集合進行 remove 和 add 等操作 IEnumerable 介面是 LINQ 特性的核心介面。只有實現了 IEnumerable 介面的集合，才能執行相關的 LINQ 操作，比如 selectwhere 等 匿名方法 匿名方法類似於函數語言程式設計中的閉包。匿名方法是透過使用 delegate 關鍵字建立委託例項來宣告的。例如： delegate void NumberChanger int n NumberChanger nc delegate int x ConsoleWriteLine Anonymous Method 0 x public void Foo object parameter ThreadPoolQueueUserWorkItem delegate anonymous delegates have full access to local variables of the enclosing method if parameter 委託的協變和逆變 委託簽名的協變和逆變。 屬性訪問器可以被單獨設定訪問級別 例子： string status stringEmpty public string Status get return status anyone can get value of this property protected set status value but only derived classes can change it 可空型別 可空型別（跟個問號，如 int i null）允許設定 null 給任何類型別。 int i null object o i if o null ConsoleWriteLine Correct behaviour runtime version from September 2005 or later else ConsoleWriteLine Incorrect behaviour prerelease runtime from before September 2005 運運算元 ：如果左運算數表示式的值不為空值時回傳該值，如果為空值則返回右運算數表示式的值。 object nullObj null object obj new Object return nullObj obj returns obj 主要用作將一個可空型別賦值給不可空型別的簡便語法 int i null int j i 0 Unless i is null initialize j to i Else if i is null initialize j to 0 C 30 的特性 C 30 釋出於 2007 年 10 月 17 日，是NET Framework 35 的一部分，它的新特性靈感來自於函數語言程式設計語言，如：Haskell 和 ML，並廣泛地引入了 Language Integrated Query（LINQ）模式到通用語言執行庫中 e Linq 語言整合查詢（，縮寫：LINQ）： 上下文相關關鍵字 from where select 可用於查詢 SQL、XML、集合等。這些識別符號在 LINQ 上下文中被作為關鍵字，但是它們的增加不會破壞原有的名為 from、where 或 select 的變數。 型別初始化器 Customer c new Customer cName James 可寫作： Customer c new Customer Name James 集合初始化器 MyList list new MyList listAdd 1 listAdd 2 可寫作 MyList list new MyList 1 2 假設 MyList 實現了 SystemCollectionsIEnumerable 且有一個 Add 方法 method 匿名型別 var x new Name James 區域性變數型別推斷 區域性變數型別推斷：var x new Dictionarystring Listfloat 等同於 Dictionarystring Listfloat x new Dictionarystring Listfloat 它只是一個語法糖，這個特性被匿名型別宣告時所需要 Lambda 表示式 Lambda 表示式（無函式名稱的物件方法在程式語言中的表達語法） listOfFooWhere delegate Foo x return xSize 10 可寫作 listOfFooWhere x xSize 10 編譯器翻譯 Lambda 表示式為強型別委託或強型別表示式樹。 注意事項： 如果只有一個引數，可以省略括號 ，例如 itemConsoleWriteLine 只有一個引數 0 的 Lambda 表示式item 如果只有一個返回值的語句，可以省略花括號 、return 關鍵字、分號，例如 item return item 2 0 改寫成：item item 2 0 Lambda 表示式可以分配給 Func，Action 或 Predicate 委託。 自動化屬性 編譯器將自動生成私有變數和適當的 getter（get 訪問器）和 setter（set 訪問器），如： public string Name get set 擴充套件方法 擴充套件方法能夠使現有的型別新增方法，而無需建立新的派生型別、重新編譯或以其它方式修改原始型別。 使用拓展方法，必須在一個非巢狀、非泛型的靜態類中定義一個靜態方法，方法第一個引數必須附加 this 關鍵字作為字首，第一個引數不能有其它修飾符（如 ref 或者 out），這個方法將被編譯器新增到該 this 的型別中。 public static class IntExtensions public static void PrintPlusOne this int x ConsoleWriteLine x 1 int foo 0 fooPrintPlusOne 注意事項： 擴充套件方法只會增加編譯器的工作，但不會影響程式執行效能（用繼承的方式為一個型別增加特性反而會影響效能） 如果原來的類中有一個方法，跟擴充套件方法一樣，那麼擴充套件方法不會被呼叫，編譯器也不會提示 分部方法 允許程式碼生成器生成方法宣告作為擴充套件點，如果有人在另一個部分類實現了它才會被包含於原始碼編譯。 分部方法（Partial methods）必須定義在分部類（partial classes）中 定義分部方法需要用 partial 做修飾符 分部方法不一定總是有執行內容的，也就是說定義的方法可以一句操作語句都沒有 分部方法返回值必須是 void 分部方法可以是靜態（static）方法 分部方法可以包含引數，引數可以包含以下修飾詞：thisrefparams 分部方法必須是私有（private）方法 例子： partial class C static partial void M int i defining declaration partial class C static partial void M int i dosomething C 40 的特性 dynamic 型別 C 40 新增 dynamic 關鍵字，提供動態程式設計（dynamic programming），把既有的靜態物件標記為動態物件，類似 javascript Python 或 Ruby。 dynamic 關鍵字標記的例項被處理成一個特殊包裝的 object 物件，取消了 CLI 的編譯時型別檢查，編譯時被假定支援任何操作，但如果並不實際支援則執行時報錯。 dynamic calc GetCalculator int sum calcAdd 10 20 具名引數與可選引數 public StreamReader OpenFile string path int bufferSize 1024 呼叫 OpenFile 時，順序可以完全顛倒： OpenFile bufferSize 4096 path footxt 與 COM 元件互動 在 C 中開啟一個 Word 檔案： static void Main string args WordApplication wordApplication new WordApplication Visible true wordApplicationDocumentsOpen Cplantdocx ReadOnly true 在 C 中指定 Excel 的某一格文字： excelObjCells 5 5Value This is sample text 泛型的協變和逆變 C 40 支援協變和逆變，例如在泛型介面可以加上 in、outzh 修飾字；zhhk 修飾字；zhcn 關鍵字。 public interface IComparerin T int Compare T left T right public interface IEnumerableout T IEnumerable IEnumeratorT GetEnumerator C 50 的特性 C Evolution Matrix Async Feature （補充： async 和 await 是一對語法糖，允許開發人員非常輕鬆的呼叫基於 TASK 的非同步程式設計）asyncawait 關鍵字並不會真的建立一個執行緒池任務，完成這個動作依賴於被呼叫方法中的函式。這一點在許多 C 的中文教程中被忽略，導致許多學習的新手誤以為 await 關鍵字會直接建立一個新的執行緒池任務。 Caller Information C 60 的特性 唯讀 Auto 屬性 Auto 屬性初始設定式 使用靜態 Null 條件運運算元 字串插值 例外狀況篩選條件 nameof 運算式 Catch 和 Finally 區塊中的 Await 索引初始設定式 集合初始設定式的擴充方法 改進的多載解析 表示式主體（Expressionbodied）用於類的方法和只讀屬性 using System public class Person public Person string firstName string lastName fname firstName lname lastName private string fname private string lname public override string ToString fname lnameTrim 返回值型別 string public void DisplayName ConsoleWriteLine ToString 返回值型別 void public string Name fname lnameTrim 只讀屬性 C 70 的特性 out 變數 能夠直接宣告一個變數在它要傳入的地方，當成一個 out 的引數 棄元 元組 物件的解構： var tuple 1 2 3 4 5 _ _ _ _ var fifth tuple 使用 isswitch 的模式匹配： var obj CultureInfoCurrentCultureDateTimeFormat switch obj case IFormatProvider fmt ConsoleWriteLine fmt object break case null ConsoleWrite A null object reference break case object _ ConsoleWriteLine Some object type without format information break if obj is object _ 對具有 out 引數的方法的呼叫： var point new Point 10 10 只要 x 不關心 y pointGetCoordinates out int x out _ 作用域內獨立使用場景： void Test Dto dto _ dto throw new ArgumentNullException nameof dto 表示式主體（Expressionbodied）用於類的屬性、構造器、終結器、索引器 using System public class Location private string locationName public Location string name Name name 建構函式 public string Name get locationName get 屬性 set locationName value set 屬性 public override string ToString GetType Name Location ConsoleWriteLine The ToString finalizer is executing 解構函式 private string types Baseball Basketball Football Hockey Soccer Tennis Volleyball public string this int i get types i 索引器 set types i value C 71 的特性 asyncMain 方法 default 常值運算式 推斷的 tuple 專案名稱 C 72 的特性 具備實值型別的參考語意 無後置具名引數 數值常值中的前置底線 private protected 存取修飾詞 C 80 的特性 可空引用型別 await yield return 可非同步返回的迭代器 Index 索引型別和 Range 區間型別 允許在宣告介面時為介面成員提供預設實現 遞迴的模式匹配 表示式形式的 Switch 關鍵字 在編譯器可做型別推斷的情況下，允許進一步省略型別宣告 C 9 的特性 新的「Record」型別 記錄型別， 是一種引用型別， 預設是不可變的。 記錄型別的相等判斷可以透過引用或者結構進行判斷的。 優點：記錄型別是輕量級的不可變型別，可以減少大量的程式碼， 可以按照結構和引用進行比較； 缺點：需要例項化大量的物件； 預設不可變的記錄型別 public record Person string Name int Age 可變記錄型別 public record MutablePerson string Name int Age public string Name get set Name public int Age get set Age var person1 new Person Alice 40 var person2 new Person Alice 40 ConsoleWriteLine person1 person2 True 結構相同 ConsoleWriteLine person1Equals person2 True 結構相同 ConsoleWriteLine ReferenceEquals person1 person2 False 引用不同 改變預設的記錄！ 建立一個新的記錄。 var person3 person1 with Age 43 ConsoleWriteLine person3 person1 False 結構不同 解構 Destruct 一個記錄， 將記錄的屬性提取為本地變數 var name age person3 var person4 new MutablePerson Alice 40 person4Age 43 記錄型別也可以被繼承 public record Citizen string Name int Age string Country Person Name Age var citizen new Citizen Alice 40 China ConsoleWriteLine person1 citizen False 型別不同； 「init」存取子 init 存取子表示該屬性所屬型別僅能在建構函式 Constructor 中或是屬性初始化式子中賦予其值，如果嘗試在其他地方設定該屬性的值，在編譯時便會遭編譯器阻止。 範例如下：在這個範例中，建立了一個 Student 型別，並且屬性 StudentName 與 StudentID 只能在初始化時賦予其值。 public class Student public Student public Student string studentNamestring studentID StudentName studentName StudentID studentID public string StudentName get init Default Name public string StudentID get init 00000000 如果在此時撰寫以下程式碼： Student DemoStudent new Student DemoStudentStudentName Test Name 編譯器便會無法編譯並且擲回錯誤。 而如果要建立學生名稱為「Test Name」，學生 ID 為「0001」的學生，則需要寫成： Student DemoStudent new Student 物件初始化運算式 StudentName Test Name StudentID 0001 或是 Student DemoStudent new Student Test Name0001 藉由型別的建構式初始化 StudentName 以及 StudentID。 最上層陳述式或稱頂級語句 在以前的版本，開發者在撰寫最上層陳述式 如 Programcs 程式碼時，需要包含完整的 namespace 與 class 架構，因此如果要撰寫 Hello World 程式時，程式碼就會是： using System namespace ConsoleApp1 class Program static void Main string args ConsoleWriteLine Hello World 但是在 C 9 之後，最上層陳述式的程式碼不需要包含 namespace 以及 class，可將其簡化為： using System ConsoleWriteLine Hello World 或者簡化為一行語句： SystemConsoleWriteLine Hello World 注意， 一個程式中， 只能有一個檔案使用頂級語句， 並且頂級語句必須位於名稱空間或型別定義之前。 lambda 棄元引數 Funcint int int zero _ _ 0 Funcint int int func delegate int _ int _ return 0 在 C 9 之前，即便不使用的 Lambda 引數也需要給它命名。C 9 支援棄元引數一方面簡化了命名，另一方面也節省了記憶體分配。更重要的是它使得程式設計的意圖更明確，讓人一看就知道這個引數是不用的，增強了程式碼的可讀性和可維護性。 只能初始化的設定器 Init only setters，只能透過物件初始化進行賦值的屬性。 public class InitDemo public string Start get init public string Stop get init initDemoStart Now Error initDemoEnd Tomorrow Error var initDemo new InitDemo Start Now Stop Tomorrow 函式指標 使用 delegate 可以宣告函式指標。 unsafe class FunctionPointer static int GetLength string s sLength delegatestring int functionPointer GetLength public void Test ConsoleWriteLine functionPointer test 4 跳過本地初始化 SystemRuntimeCompilerServicesSkipLocalsInit static unsafe void DemoLocalsInit int x 注意， x 沒有初始化， 輸出結果不確定； ConsoleWriteLine x 原生整數型別 兩個新的整數型別 nint 和 nunit ， 依賴宿主機以及編譯設定。 協變返回型別 協變返回型別為重寫方法的返回型別提供了靈活性。覆蓋方法可以返回從被覆蓋的基礎方法的返回型別派生的型別。 class Person public virtual Person GetPerson return new Person class Student Person public override Student GetPerson return new Student 模組初始化程式碼 ModuleInitializerAttribute 為元件 assembly 定義初始化程式碼， 當初始化 載入時執行， 可以類比類的靜態建構函式， 但是是元件級別的。 必須是靜態的、無引數的、無返回值的方法； 不能是範型方法，也不能包含在範型類中； 不能是私有函式，必須是公開 public 或者內部 internal 的函式； 靜態 lambda 表示式 static 修飾符新增到 lambda 表示式或匿名方法 。這將無法捕獲區域性變數或例項狀態，從而防止意外捕獲其他變數。 分部方法擴充套件 移除了分部方法的下述限制： 必須具有 void 返回型別。 不能具有 out 引數。 不能具有任何可訪問性（隱式 private ）。 初始化表示式的簡化 如果建立物件的型別已知時，可以在 new 表示式中省略該型別。 Point p new 1 1 Dictionarystring int dict new Point points new 1 1 new 2 2 new 3 3 var list new ListPoint new 1 1 new 2 2 new 3 3 在本地函式上新增標記 using SystemDiagnostics using SystemDiagnosticsCodeAnalysis namespace CoreApp2 class Program static void Main string args Conditional DEBUG static void DoSomething NotNull string test SystemConsoleWriteLine Do it DoSomething Doing GetEnumerator 擴充套件 可以為任意型別新增一個 GetEnumerator 擴充套件方法， 返回一個 IEnumerator 或者 IAsyncEnumerator 例項， 從而在 foreach 迴圈中使用。 using SystemCollectionsGeneric using SystemCollectionsObjectModel namespace CoreApp2 public static class Extensions public static IEnumeratorT GetEnumeratorTthis IEnumeratorT enumerator enumerator class Program static void Main string args IEnumeratorstring enumerator new Collectionstring A B CGetEnumerator foreach var item in enumerator ConsoleWriteLine item 模式匹配增強 Type patterns 型別匹配，判斷一個變數的型別 object obj new int var type obj switch string string int int _ obj ConsoleWriteLine type int Relational patterns 關係匹配： class Person public string name public int age public Person string a int b name aage b public void Deconstruct out string aout int ba nameb age class Program static void Main string args var person1 new Person Alice 40 var inRange person1 switch _ 18 less than 18 _ 18 greater than 18 _ 18 18 years old ConsoleWriteLine inRange greater than 18 Conjunctive and patterns 邏輯合取匹配： And pattern var person1 new Person Alice 40 var ageInRange person1 switch _ 18 less than 18 Zhang Zhimin _ and _ 18 Alice is greater than 18 ConsoleWriteLine ageInRange Alice is greater than 18 Disjunctive or patterns 邏輯析取匹配： Or pattern var person1 new Person Alice 40 var ageInRange person1 switch _ 18 less than 18 _ 18 or _ 18 18 or greater ConsoleWriteLine ageInRange 18 or greater Negated not patterns 邏輯非匹配 Not pattern var person1 new Person Alice 40 var meOrNot person1 switch not Alice 40 Not me _ Me ConsoleWriteLine meOrNot Me Parenthesized patterns 帶括號的優先順序匹配： Parenthesized patterns var is10 new IsNumber true 10 var n10 is10 switch _ 1 and 5 and _ 5 and 9 or _ 10 10 _ not 10 ConsoleWriteLine n10 10 C 10 的特性 record struct 解決了 record 只能給 class 而不能給 struct 用的問題： record struct Point int X int Y sealed record ToString 方法 可以把 record 裡的 ToString 方法標記成 sealed struct 無參建構函式 無參建構函式使得 new struct 和 default struct 的語義不一樣 用 with 建立新的匿名型別物件 var x new A 1 B 2 var y x with A 3 這裡 yA 將會是 3 。 全域性的 using 可以給整個專案啟用 using，不需要每個檔案都寫一份。 檔案範圍的 namespace 以前寫 namespace 還得帶一層大括號。現在如果一個檔案裡只有一個 namespace 的話，直接在檔案開頭寫：namespace MyNamespace 常量字串插值 const string x hello const string y x world lambda 的改進 lambda 可以帶 attributes f Foo x x 給 lambda 設定 f return Foo x x 給 lambda 返回值設定 f Foo x x 給 lambda 引數設定 指定返回值型別 此前 C 的 lambda 返回值型別靠推導，C 10 允許在引數列表之前顯式指定 lambda 返回值型別： f int 4 支援 ref 、in 、out 等修飾 f ref int ref int x ref x 返回一個引數的引用 頭等函式 函式可以隱式轉換到 delegate，於是函式上升為頭等函式 first function： void Foo ConsoleWriteLine hello var x Foo x hello 自然委託型別 lambda 可自動建立自然委託型別，於是不再需要寫出型別： var f 1 Funcint var g string int x string y yx Funcint string string var h testGetHashCode Funcint CallerArgumentExpression 使用 CallerArgumentExpression 這個 attribute，編譯器會自動填充呼叫引數的表示式字串，例如： void Foo int value CallerArgumentExpression value string expression null ConsoleWriteLine expression value 當你呼叫 Foo 4 5 時，會輸出 4 5 9。這對測試框架極其有用 tuple 的混合定義和使用 int y 0 var x y var z 1 2 3 於是 y 就變成 2 了，同時還建立了兩個變數 x 和 z，分別是 1 和 3 。 介面支援抽象靜態方法 NET 6 中這個特性為 preview 特性。 泛型 attribute 在方法上指定 AsyncMethodBuilder 在方法上用 AsyncMethodBuilder ，來使用自己實現的 async method builder，代替自帶的 Task 或者 ValueTask 的非同步方法構造器。有助於實現零開銷的非同步方法。 line 指示器支援行列和範圍 以前 line 只能用來指定一個檔案中的某一行，現在可以指定行列和範圍： line startLine startChar endLine endChar charOffset fileName 比如 line 1 1 2 2 3 testcs 巢狀屬性模式匹配改進 以前在匹配巢狀屬性的時候需要這麼寫： if a is X Y Z 4 現在只需要簡單的： if a is XYZ 4 改進的字串插值 實現接近零開銷的字串插值。 Source Generator v2 包括強型別的程式碼構建器，以及增量編譯的支援等 C 11 的特性 泛型屬性 C 11 開始支援屬性（attribute）為泛型類，即允許宣告基類為 SystemAttribute 的泛型類： public class GenericAttributeT Attribute 靜態介面方法 C 11 開始允許介面中定義靜態方法（包括運算子過載方法），實現該介面的類必須包含該靜態方法： public interface IGetNextT where T IGetNextT static abstract T operator T other 無符號右移運算子 新增無符號右移運算子 ，用於對帶符號數進行邏輯右移。 泛型數學支援 對泛型及其物件進行數學操作的支援。基於靜態介面方法特性，自 NET 80 起，在 System 名稱空間中提供數學運算相關泛型介面，以支援泛型的運算操作： public static TResult SumT TResultIEnumerableT values where T INumberT where TResult INumberTResult TResult result TResultZero foreach var value in values result TResultCreate value return result 字串內插中的換行符 允許內插字串中 與 內的文字跨多個行 原始字串文字 原始字串文字以 開始並以 結束，允許多行字串，若為多行字串則以單獨的一行 結束，且字串的縮排以末尾的 的起始位置為基準。原始字串文字不進行任何轉義操作，但允許字串內插（開頭的 數量代表內插所需要的花括號數）： var x 1 var y 2 var code1 int i 0 var code2 int x x var code3 include stdioh int main void const char s y y y 2 return 0 ConsoleWriteLine code1n code1n ConsoleWriteLine code2n code2n ConsoleWriteLine code3n code3n UTF8 字串字面量 可以對字串字面量指定 u8 字尾來指定 UTF8 字元編碼的字串字面量，其型別為 ReadOnlySpanbyte： 列表模式 使用 和 可以定義列表模式，用於模式匹配： int numbers 1 2 3 ConsoleWriteLine numbers is 1 2 3 True ConsoleWriteLine numbers is 1 2 4 False ConsoleWriteLine numbers is 1 2 3 4 False ConsoleWriteLine numbers is 0 or 1 2 3 True 數值 IntPtr 和 UIntPtr C 11 起 nint 和 nuint 型別的別名分別為 IntPtr 和 UIntPtr（C 9 中它們僅被認為是 相似 的）。 改進了方法組向委託的轉換 優化了方法組向委託轉換的效能。例如下述程式碼中，在 C 11 前，Sum 比 SumMethodGroup 效能更高： static readonly Listint Numbers EnumberableRange 0 100ToList public int Sum return NumbersWhere x Filter xSum faster public int SumMethodGroup return NumbersWhere FilterSum slower static bool Filter int number return number 50 C 13 的特性 params 集合 params 修飾符不再僅限於陣列型別。現在可以將 params 用於任何已識別的集合型別，包括 SystemSpanT、SystemReadOnlySpanT 以及實現 SystemCollectionsGenericIEnumerableT 並具有 Add 方法的型別。除了具體型別外，介面 SystemCollectionsGenericIEnumerableT、SystemCollectionsGenericIReadOnlyCollectionT、SystemCollectionsGenericIReadOnlyListT、SystemCollectionsGenericICollectionT 和 SystemCollectionsGenericIListT 也可以使用。 當使用介面型別時，編譯器會合成提供的引數的儲存。詳情請參考 Params collections 的功能規範。 新的鎖物件 NET 9 執行時引入了一種新的執行緒同步型別 SystemThreadingLock，該型別透過其 API 提供了更好的執行緒同步。LockEnterScope 方法進入一個排他作用域，返回的 ref struct 支援 Dispose 模式以退出排他作用域。C 的 lock 語句識別 Lock 物件，並使用更新的 API，而不是傳統的 SystemThreadingMonitor API。如果將 Lock 物件轉換為其他型別，編譯器會生成基於 Monitor 的程式碼。詳情請參考該物件的功能規範。 新的 ESCAPE 轉義序列 可以使用 e 作為 ESCAPE 字元 Unicode U001B 的字面值轉義序列。 在該版本以前，ESCAPE 使用的是 u001b 或 x1b。 不建議使用 x1b，因為如果 1b 後面的下一個字元是有效的十六進位制數字，則那些字元會成為轉義序列的一部分。 方法組自然特性 該特性對涉及方法組的過載解析進行了小幅最佳化。方法組是指具有相同名稱的所有過載方法。此前，編譯器會構建方法組的完整候選方法集，並從中確定自然型別。新的行為是在每個作用域修剪候選方法集，移除不適用的方法（通常是具有錯誤泛型引數或不滿足約束的泛型方法）。如果在給定作用域中找到的所有候選方法都不匹配，則方法組沒有自然型別。 以下是新行為的具體改進： 概述 優化了方法組自然型別的確定： 按作用域逐步考慮候選方法（首先是例項方法，然後是每個後續作用域的擴充套件方法）。 修剪沒有成功機會的候選方法，以免它們干擾確定唯一簽名： 當沒有提供型別引數時，修剪泛型例項方法（如 var x M）。 基於是否能減少擴充套件和約束來修剪泛型擴充套件方法。 背景 在 C 10 中，方法組獲得了一種弱自然型別。這種型別是 弱型別，僅在方法組未被目標型別化時才會發揮作用（即它在 SystemAction a MethodGroup 中不起作用）。這種弱自然型別允許諸如 var x MethodGroup 的場景。 方法組在所有候選方法具有共同簽名時具有自然型別。如果方法組可能包含擴充套件方法，則候選方法包括包含型別和所有擴充套件方法作用域。 應用 在實踐中，這意味著我們將： 構建所有候選方法的集合： 如果方法在相關型別上，如果它們是靜態的且接收者是型別，或者它們是非靜態的且接收者是值，則這些方法在集合中。 可以減少的所有作用域中的擴充套件方法也在集合中。 如果所有候選方法的簽名不匹配，則方法組沒有自然型別。 如果結果簽名的引數數量與提供的型別引數數量不匹配，則方法組沒有自然型別。 否則，結果簽名將用作自然型別。 提案 原則是按作用域逐步進行，並儘早修剪我們知道無法成功的候選方法（與過載解析中使用的原則相同）。 對於每個作用域，我們構建所有候選方法的集合： 對於初始作用域，如果方法在相關型別上且其引數數量與提供的型別引數數量匹配，並且滿足提供的型別引數的約束，則這些方法在集合中；如果它們是靜態的且接收者是型別，或者它們是非靜態的且接收者是值。 對於後續作用域，如果擴充套件方法可以用提供的型別引數替換，並使用接收者的值進行減少，同時滿足約束，則這些方法在集合中。 如果在給定作用域中沒有候選方法，則繼續到下一個作用域。 如果所有候選方法的簽名不匹配，則方法組沒有自然型別。 否則，結果簽名將用作自然型別。 如果所有作用域都已耗盡，則方法組沒有自然型別。 隱式索引訪問 現在可以在物件初始化表示式中使用隱式 從末尾 索引運算子 。 例如，可以在物件初始化器中初始化陣列： var countdown new TimerRemaining buffer 1 0 2 1 3 2 4 3 5 4 6 5 7 6 8 7 9 8 10 9 上述示例建立了一個從 9 到 0 遞減的陣列。 在 C 13 之前， 運算子不能在物件初始化器中使用，必須從前面索引元素。 迭代器和非同步方法中的 ref 和 unsafe 在 C 13 之前，迭代器方法（使用 yield return 的方法）和非同步方法不能宣告本地 ref 變數，也不能有 unsafe 上下文。在 C 13 中，非同步方法可以宣告本地 ref 變數或 ref struct 型別的本地變數，但這些變數不能跨越 await 邊界訪問。同樣，它們也不能跨越 yield return 邊界訪問。這一放寬的限制使編譯器能夠在更多地方允許可驗證的安全使用 ref 本地變數和 ref struct 型別。你可以在這些方法中安全地使用 SystemReadOnlySpanT 等型別。如果違反了安全規則，編譯器會發出警告。 ref struct 介面 在 C 13 之前，ref struct 型別不能實現介面。從 C 13 開始，它們可以實現介面。為了確保 ref 安全規則，ref struct 型別不能轉換為介面型別。這是一種裝箱轉換，可能違反 ref 安全。 allows ref struct 在 C 13 之前，ref struct 型別不能作為泛型型別或方法的型別引數宣告。現在，泛型型別宣告可以新增反約束 allows ref struct。這種反約束宣告該型別引數提供的型別引數可以是 ref struct 型別。編譯器在該型別引數的所有例項上強制執行 ref 安全規則。這使得 SystemSpanT 和 SystemReadOnlySpanT 等型別可以在適用的地方與泛型演算法一起使用。 詳情請參閱 where 更新和泛型約束程式設計指南文章。 更多的部分成員 在 C 13 中，可以宣告分部屬性和分部索引器。分部屬性和索引器通常遵循與分部方法相同的規則：建立一個宣告宣告和一個實現宣告。兩個宣告的簽名必須匹配。一個限制是不能為分部屬性使用自動屬性宣告。未宣告主體的屬性被視為宣告宣告。詳情請參閱 Partial members 文章。 過載解析優先順序 在 C 13 中，編譯器識別 OverloadResolutionPriorityAttribute 以優先選擇一個過載而不是另一個。庫作者可以使用此屬性確保新的、更好的過載優先於現有過載。例如，你可能會新增一個性能更高的新過載。你不希望破壞使用你庫的現有程式碼，但希望使用者在重新編譯時更新到新版本。你可以使用過載解析優先順序來通知編譯器應優先選擇哪個過載。優先順序最高的過載會被優先選擇。此功能旨在幫助庫作者在新增新過載時避免歧義。庫作者應謹慎使用此屬性以避免混淆。 程式的執行 C 通常不被編譯成為能夠直接在計算機上執行的二進位制原生代碼。與 Java 類似，它被編譯成為中間程式碼（Microsoft Intermediate Language），然後透過NET Framework 的虛擬機器 被稱為 zhhans 通用語言執行庫；zhhant 通用語言執行層 執行。 所有的Net 程式語言都被編譯成這種被稱為通用中間語言的中間程式碼。因此雖然最終的程式在表面上仍然與傳統意義上的可執行檔案都具有 exe 的字尾名。如果計算機上沒有安裝Net Framework，那麼這些程式會彈出對話方塊，要求使用者下載net framework。 在程式執行時，Net Framework 將中間程式碼翻譯成為二進位制機器碼，從而使它得到正確的執行。最終的二進位制程式碼被儲存在一個緩衝區（Buffer）中。所以一旦程式使用了相同的程式碼，那麼將會呼叫緩衝區中的版本。這樣如果一個Net 程式第二次被執行，那麼這種翻譯不需要進行第二次，速度明顯加快。 標準化 微軟公司已經向 ECMA 申請將 C 作為一種標準。在 2001 年 12 月，ECMA 釋出了 ECMA334 C 語言規範。C 在 2003 年成為一個 ISO 標準（ISOIEC 23270）。現在有一些獨立的實現正在進行，包括： 自由軟體基金會的 dotGNU PortableNET Mono Baltie C IDE for children and young Baltie 示例 C 的 Hello World 程式 下面是一個在 zh 命令列；zhhans 命令列；zhhant 命令提示字元 上輸出 Hello World 的小 zh 程式；zhhans 程式；zhhant 程式，這種 zh 程式；zhhans 程式；zhhant 程式 通常作為開始學習 zh 程式；zhhans 程式；zhhant 程式 語言的第一個步驟： using System namespace ConsoleApp1 class Program static void Main string args ConsoleWriteLine Hello World 實現 微軟正在引領開源參考 C 編譯器和工具集的開發。 第一個編譯器 Roslyn 編譯成中間語言（IL），第二個編譯器 RyuJIT， 是一個 JIT（即時）編譯器，它是動態的，進行動態最佳化並編譯將 IL 轉換為 CPU 前端的本機程式碼。 RyuJIT 是開源的，用 C 編寫。 Roslyn 完全是用 託管程式碼 C 編寫的，已經開放並且功能以 API 的形式出現。因此，它使開發人員能夠建立重構和診斷工具。 官方實現的兩個分支是 NET Framework（閉源，僅限 Windows）和 NET Core（開源，跨平臺）；它們最終融合為一個開源實現：NET 50。 在 NET Framework 46 中，新的 JIT 編譯器取代了前者。 其他 C 編譯器（其中一些包括公共語言基礎結構和 NET 類庫的實現）： 微軟的 zhRotorzhhansRotorzhhant 轉軸 專案（Rotor Project，目前稱為），提供了 zhhans 通用語言執行庫；zhhant 通用語言執行層（Common Language Runtime）的實作與 C 編譯器。但是 Shared Source Common Language Infrastructure 在 2006 年的 20 版後就停止了。 由 Microsoft 贊助的 Mono zh 專案；zhhans 專案；zhhant 專案 提供了 C 編譯器，它提供了一個開源 C 編譯器、一個完整的 CLI 開源實現，同時也接近百分之百地實作了NET Frameworkzh 類庫；zhhans 類庫；zhhant 類別庫。而 Mono 後來衍伸出由微軟認可的第三方套件 Xamarin。 Dot GNU 專案（現已停產）也提供了另一個自由版本的 C 編譯器，也提供了NET Frameworkzh 類庫；zhhans 類庫；zhhant 類別庫 的實作。 遊戲引擎 Unity 使用 C 作為其主要指令碼語言。由於 Microsoft 捐贈了 24000 美元， Godot 遊戲引擎實現了一個可選的 C 模組。 參考文獻 外部連結 C Language Specification MSDN ECMA334 C Language Specification pdf ISOIEC 232702003 C Language Specification Visual Studio Code Download NET Visual C NET 入門 MSDN MCS Mono C 編譯器 Visual Studio Community Visual C Logo C 教學 C 教材目錄 CategoryNET 程式語言 CategoryC 語言家族 Category 面向物件的程式語言 Category 基於類的程式語言 CategoryEcma 標準 Category2000 年建立的程式語言