文章目錄
- 前言
- 名詞解釋
- 主要版本一覽表
- 各版本主要特性一句話總結
-
- C# 1.0 (Visual Studio 2002, .Net Framework 1.0)
- C# 2.0 (Visual Studio 2005, .Net Framework 2.0)
- C# 3.0 (Visual Studio 2008, .Net Framework 3.0)
- C# 4.0 (Visual Studio 2010, .Net Framework 4)
- C# 5.0 (Visual Studio 2012, .Net Framework 4.5)
- C# 6.0 (Visual Studio 2015, .Net Framework 4.6)
- C# 7.0 (Visual Studio 2017, .Net Framework 4.7)
- C# 8.0 (Visual Studio 2019 .Net Framework 4.8)
- C# 9.0 (Visual Studio 2019, .Net 5.0)
- C# 10 (Visual Studio 2022, .Net 6.0)
- C# 11 (Visual Studio 2022, .Net 7.0)
- C# 12 (Visual Studio 2022,.Net 8.0)
- 日志
- 參考資料
前言
從2002年.Net平臺發布開始,C#已經從1.0更新到了現在的8.0。目前網上有很多文章對這些版本的主要更新內容進行了總結,但是大都是內容的簡單翻譯和資料堆疊。本文根據自己的使用體驗,在現有總結的基礎上進行內容豐富細化,以便于讀者能夠對C#的語言特性有更加詳細深刻的認識和理解。
自從上世紀90年代Java火了以后,微信就想做自己的Java,于是從1998年開始就制定了.NET計劃,并于2002年正式發布。而C#就是.NET平臺開發的首發語言,其主要參考對象為Java(熟悉這兩門語言的朋友會發現兩者有非常多的相似性),并結合VC6.0的界面設計方式、MFC的類庫等為一體,整合而來。從C#1.0語言誕生開始,微軟就不斷為其添磚加瓦,豐富其功能。使其始終保持活躍的生命力。
名詞解釋
- C#?一門專門為 .NET 而推出的編程開發語言,對應Java
- .NET Framework?C#的運行環境,對應 JDK。
- .Net?微軟從C#9開始,將其真正開源做跨平臺,包括5,6,7,8等版本。
- Visutal Studio?開發環境即IDE,對應 Eclipse。
主要版本一覽表
C# 版本 | 發布時間 | 對應 .Net 框架版本 | 對應Visual Studio版本 |
---|---|---|---|
C# 1.0 | 2002.01 | .NET Framework 1.0/1.1 | Visual Studio 2002 |
C# 2.0 | 2005.11 | .NET Framework 2.0 | Visual Studio 2005 |
C# 3.0 | 2007.11 | .NET Framework 3.0/3.5 | Visual Studio 2008 |
C# 4.0 | 2010.04 | .NET Framework 4.0 | Visual Studio 2010 |
C# 5.0 | 2012.08 | .NET Framework 4.5 | Visual Studio 2012 |
C# 6.0 | 2015.07 | .NET Framework 4.6 | Visual Studio 2015 |
C# 7.0 | 2017.03 | .NET Framework 4.7.1~4.7.3 | Visual Studio 2017 |
C# 8.0 | 2019.09 | .NET Framework 4.8 | Visual Studio 2019 |
C# 9.0 | 2020.11 | .NET 5 (跨平臺統一命名) | Visual Studio 2020 |
C# 10.0 | 2021.11 | .NET 6 | Visual Studio 2022 |
C# 11.0 | 2022.11 | .NET 7 | Visual Studio 2022 |
C# 12.0 | 2023.11 | .NET 8 | Visual Studio 2022 |
我們在新建項目的時候所要選擇的就是.NET Framework的版本號。如下圖所示:
各版本主要特性一句話總結
C# 1.0 (Visual Studio 2002, .Net Framework 1.0)
回過頭來看看,C#1.0版本看起來很像Java。當時的設計目標是成為一種“簡單,現代,通用的面向對象語言”。 當時,看起來像Java意味著它實現了那些早期的設計目標。但如果現在回顧一下C#1.0,你會發現它的功能很弱:缺乏內置的異步功能和一些我們認為理所當然的泛型功能。 比如,沒有泛型、LINQ、Lambda表達式。與今天相比,C#版本1.0看起來被剝奪了功能。 你會發現自己編寫了一些冗長的代碼。 但是,你必須從某個地方開始。這個版本的特性就不列出來了,可以理解為最開始的基本功能的C#。如果沒有后面微軟的不斷更新,則不會有C#的今天,因為它很快就會被更多的語言替代而被人遺忘。
C# 2.0 (Visual Studio 2005, .Net Framework 2.0)
微軟在 Studio 2005 中發布了C#2.0。在此版本中,主要引入了很多新特性(比如非常重要的泛型),以幫助開發人員以更通用的方式編寫應用程序代碼。 以下是C#2.0引入的新功能:
- Generics
泛型,如經常使用的?List<String> list = new List<String>();
- Partial types
分部類型,可以將類、結構、接口等類型定義拆分到多個文件中,如在窗體設計類中,就有兩個文件 Form.cs 和 Form.designer.cs 將業務邏輯和界面設計分離 - Anonymous methods
匿名方法,即可以在不定義函數名稱和參數列表的情況直接定義函數,主要的使用是方便調用代理。 - Iterators
迭代器,即?foreach
?語法 - Nullable types
可以為Null的類型,該類可以是其它值或者null,便于空值的判斷 - Getter/setter separate accessibility
屬性訪問和設置權限分享,即可以分別設置getter 和 setter 的可訪問性。 - Method group conversions (delegates)
方法組轉換,可以將聲明委托代表一組方法,隱式調用 - Co- and Contra-variance for delegates and interfaces
委托、接口的協變和逆變,主要用于擴大委托的定義范圍,具體參見文章:快速理解C#委托中的協變與逆變。 - Static classes
靜態類,即可以定義一個類為 static,從而保證其唯一性 - Delegate inference
委托推斷,允許將方法名直接賦給委托變量,從而簡化操作
C# 3.0 (Visual Studio 2008, .Net Framework 3.0)
- Implicitly typed local variables
可以使用var關鍵字,如?var s = "tom"
,從而不用在定義時明確指定數據類型,方便使用。 - Object and collection initializers 對象和集合初始化器
對象初始化器:Person tom = new Person(){ ID = 0, Name = "Tom"};
集合初始化器:List<string> names = { "Tom", "Jack", "Lucy"};
- Auto-Implemented properties 自動屬性,自動生成屬性方法,聲明更簡潔
示例:?public string Name{get;set;}
- Anonymous types 匿名類型
示例:先定義?var tom= new { ID = 0, Name = "Tom" };
?再使用?Console.WriteLine($"Name = {tom.Name}");
。 - Extension methods:擴展方法
即可以給一個已經封裝好的類添加新的方法(注意:不是派生)。 - Query Expressions
查詢表達式提供了兩種全新的表達語言:Lambda 表達式
?和?表達式樹(Expression trees)
。其中,表達式樹是以樹形數據結構表示代碼,是一種新數據類型,具體參見:表達式樹。表達式樹存在的主要目的就是可以根據需求的不同從而動態修改表達式樹中的表達式以便生成可在非C#環境執行的代碼。 - Partial methods
在C#2.0中引入了類,其目的是實現前臺和后臺的分離。但是在實際應用中,有時候一些方法仍然需要前后臺的人員進行共同合作才能解決。為了處理這個問題,引入了分部方法,即可以在一個部分類中引入聲明,在另一個相同的分部類中進行定義。如下所示:
定義部分:public partial class Form1: Form { partial void method();}
實現部分:partial class Form1: Form { partial void method (){ Console.WriteLine("Partial method");}
即便沒有實現,編譯的時候也可以正常通過,以方便設計和開發人員。
C# 4.0 (Visual Studio 2010, .Net Framework 4)
- Dynamic binding
C#3.0 提供了?var
?關鍵字,可以自動推斷數據類型,4.0 又提供了一個看上去類似的?dynamic
。這個關鍵字也是用于定義對象,并且也不需要知道數據類型,即可調用對象的方法,但是區別在于?var
?是根據上下文推斷數據類型,然后再調用,而?dynamic
?是不對類型進行檢測,即便對象是?object
?類型,調用一個未知的方法也不會報錯。因為它會在程序運行時,真正執行到所在行的時候才會進行判斷,如果對象中有調用的方法,則正常調用,否則就會報錯,具體可以參見:?C#中dynamic的正確用法。 - Named and optional arguments
中文翻譯為:具名參數和可選參數。
可選參數:即為參數加上默認值,如?void show(string msg="info"){ Console.WriteLine(msg);}
,在調用時可以不寫參數,即:show()
,此時?msg
?的值為?info
。
具名函數:若可選參數的函數定義為:int add(int x = 1, int y)
,那么在調用時第1個省略后就會報錯,所以可以使用具名函數調用,調用方法為:add(y:5);
,此時?x
?為默認值,y
?為 5。
即具體可以參見這篇文章:C#中的 具名參數 和 可選參數。 - Generic co- and contravariance
泛型的協變和逆變,原理同C#2.0委托、接口的協變和逆變。 - Embedded interop types (“NoPIA”)
中文翻譯為:嵌入互操作類型。表示嵌入類型信息,增加引用COM組件程序的中立性,主要用于COM模塊的調用。具體可以參閱這篇文章:C# 嵌入互操作類型。
C# 5.0 (Visual Studio 2012, .Net Framework 4.5)
- Asynchronous methods
用于多線程編程,可以異步調用方法,請參閱:C#異步編程方式以及示例。 - Caller info attributes
調用方信息特性。主要作用是可以顯示調用函數的名稱、所在文件和所在行的信息。基主要目的是為了便于調試。具體可以參見這篇文章:http://www.itstrike.cn/Question/99a193ca-e99a-45ba-99f1-1f38017313db - 其他
實際上5.0的新特性肯定不會只有兩條,但是了由于特性不是很明顯,于是就不再詳細介紹,具體可以參見:C# 5.0五大新特性。
C# 6.0 (Visual Studio 2015, .Net Framework 4.6)
- Import of static type members into namespace
用于簡化書寫。在引用類名后,可以直接使用類的靜態成員,比如在使用?using static System.String;
?后,可以將?String.IsNullOrEmpty(str)
?可以直接寫成?IsNullOrEmpty(str)
。 - Exception filters
異常過濾器,即在異常的時候可以進行刪除,比如定義一個變量?int level;
,那么在可以使用這樣的語法:try{
doSomething();
} catch(Exception e) when (level == 10){
ProcessException(e);
}
這樣,只有在?level == 10
?的時候,才會進行異常處理。 - Await in catch/finally blocks
支持在catch/finally語句塊使用await語句進行異常調用 。 - Auto property initializers
自動屬性的初始化。這個非常好用,可以在定義屬性時直接賦值,比如?public string Name { get; set; } = "no name";
。 - Default values for getter-only properties
即給只讀屬性設置默認值,如?public string Name { get; } = "no name";
。 - Expression-bodied members
表達式主體成員指的是僅以表達式定義的成員。舉例來說:一個類中有個?public string Name {get; set}
?屬性,在?ToString()
?方法重寫的時候,我們需要以下格式:public override string ToString() { return $"{Name}".Trim();}
現在優化后,同樣也可以使用 Lambda 的操作符號?=>
?進行簡化,簡化后為:public override string ToString() => $"{Name}".Trim();
注:當代碼有多行的時候,使用一對花括號分隔,但是右花括號后要以分號結束。 - Null propagator (null-conditional operator, succinct null checking)
Null條件操作符,用法有兩種:
1)非空時才調用,如?obj?.ToString();?
,如果?obj
?不為空,則執行?obj.ToString();
,否則跳過不執行此行。相當于?if(obj != null) obj.ToString();
。
2)string s = obj ?? obj.ToString();?
,作用同上。 - String interpolation
字符串插入拼接。用于簡化字符串的拼接。這個超級好用,比如說:?string s1 = "John", s2 = "Corner";
?如果想得到?"Jone Corner"
,原來的方法要么拼接,即?s1 + " " + s2
,要么使用?String.Format
。新方法很簡單:$"{s1} {s2}"
,實際上就是對String.Format
的簡化,而且在?{}
中非常強大,可以所有常規的表達式,甚至直接支持雙引號,比如:?$"{DateTime.Now.ToString("yyyy/MM/dd")}"
?輸出為?2019/08/28
。 - nameof operator
新加入的關鍵字?nameof
,用于返回方法、屬性、變量的名稱,如?string name = nameof(String.Format);
,返回?Format
。很多時候,我們如果直接使用字符串,當名稱變更的時候會不好用,而使用了?nameof
?的時候,可以直接與方法、屬性、變量等名稱關聯,即便這個變量的名稱發生變化了,使用?nameof
?以后,也會跟著一起變化,這個在動態編輯時很有用。 - Dictionary initializer
字典初始化。格式如下所示:var moreNumbers = new Dictionary<int, string>
{
{19, "nineteen" },
{23, "twenty-three" },
{42, "forty-two" }
};
C# 7.0 (Visual Studio 2017, .Net Framework 4.7)
- Out variables
可以在out后面直接聲明變量,例如前TryParse需要先定義再使用的兩行的代碼,現在一行即可:?int.TryParse(s, out int num)
,從而簡化語法。 - Pattern matching
數據類型轉換的語法糖。可以在類型判斷同時定義符合的變量。如變量?object obj
,判斷其是否是int,并進行求和。
之前的寫法:if (obj is int) sum += (int)obj;
C# 7的寫法:if (item is int val) sum += val;
由以可見,在判斷時自動定義了轉換好的值,從而簡化代碼。除了 if 語句,在 switch 語句中也同樣適用。 - Tuples
元組改進,可以為無組添加名稱,用法:
方式1:定義:(int one, int two) tuple = (1, 2);
?使用:?WriteLine($"first:{tuple.one}, second:{tuple.two}");
。
方式2:定義:var tuple2 = (one: 1, two: 2);
?使用:?WriteLine($"first:{tuple2.one}, second:{tuple2.two}");
。 - Deconstruction
可以從一個類的構造函數中提取相應的數據,比如:var (Name, Age) = new Person(Name, Age);
。 - Local Functions
在函數中定義子函數,子函數體放在 return 后面。這個相關于C++中的inline,用于提高效率,一般非性能場合不推薦使用,因為它不僅影響了程序的閱讀性,而且也不利于代碼管理。 - Binary Literals
二進制使用?0b
表示,如?var one= 0b000_0001
; - Digit Separators
在數字中使用下劃線作為分隔符,這個是為了增強代碼的可讀性。例如,1000000,可以寫成 1_000_000。 - Ref returns and locals
對ref引用進行了加強,現在可以引用一個方法中的局部變量,語法是:在方法定義前加上 ref,同時在返回時也加上ref,如定義函數ref int GetDataRef(int[] data, int index){ return ref data[index];}
?,則?ref int num = ref GetDataRef(new data[]{1,2,3}, 0);
?返回,對數組中第0個元素的引用。 - Generalized async return types
如名稱所示,現在泛型也支持async。 - More expression-bodied members
進一步豐富C#6中的表達式成員的功能,允許構造器、解析器、屬性可以使用表達式作為body。比如屬性:public string Name{ get => name; set => name = value ?? "noname";}
- Throw expressions
Throw可以拋出表達式中。如果表達式成立,則拋出表達式的值,類型為System.Exception,如果值為 null,則拋出System.NullReferenceException。
更多:下面是 7.1-7.3在更新的一些屬性,僅供參考。
- C# 7.1 特征 (Visual Studio 2017 version 15.3)
Async main:在main方法用async方式
Default expressions:引入新的字面值default
Reference assemblies:
Inferred tuple element names:
Pattern-matching with generics: - C# 7.2 特征 (Visual Studio 2017 version 15.5)
Span and ref-like types
In parameters and readonly references
Ref conditional
Non-trailing named arguments
Private protected accessibility
Digit separator after base specifier - C# 7.3 (Visual Studio 2017 version 15.7)
重載解析
泛型約束:枚舉、委托和非托管
隱藏字段的Attribute
元組比較(==和!=)
棧分配Span
可重新賦值的Ref局部變量
初始化器中的表達式變量
棧分配數組
C# 8.0 (Visual Studio 2019 .Net Framework 4.8)
參考網頁?官網:C# 8.0 中的新增功能
- Readonly 成員?參考
添加了readonly關鍵字的函數,不能修改類內成員,從而保證數據的只讀性。如以下代碼會報錯。
public struct Vector2{public float x,y; public readonly float GetLengthIllegal(){var tmp = MathF.Sqrt(LengthSquared); x = tmp; // Compiler error, cannot write xy = tmp; // Compiler error, cannot write y return tmp;}
}
-
默認接口方法
-
模式匹配增強功能:
-
Switch 表達式
-
屬性模式
-
元組模式
-
位置模式
-
Using 聲明
-
靜態本地函數
-
可處置的 ref 結構
-
可為空引用類型?ref
增加了可空類型,使用?type?
?表示,如?string?
?表示可空字符串。好處就是string?
?可能為空,而?string
?就一定不為空,這樣可以省去判斷。 -
異步流
-
異步可釋放
-
索引和范圍
-
Null 合并賦值
-
非托管構造類型
-
嵌套表達式中的 Stackalloc
-
內插逐字字符串的增強功能
參考:官網
C# 9.0 (Visual Studio 2019, .Net 5.0)
參考網頁?官網:C# 9.0 中的新增功能
- 記錄
- 僅限 Init 的資源庫
- 頂級語句
- 模式匹配增強功能
- 性能和互操作性
- 本機大小的整數
- 函數指針
- 禁止發出 localsinit 標志
- 調整和完成功能
- 目標類型的 new 表達式
- static 匿名函數
- 目標類型的條件表達式
- 協變返回類型
- 擴展 GetEnumerator 支持 foreach 循環
- Lambda 棄元參數
- 本地函數的屬性
- 支持代碼生成器
- 模塊初始值設定項
- 分部方法的新功能
C# 10 (Visual Studio 2022, .Net 6.0)
參考網頁?官網:C# 10.0 中的新增功能
- 記錄結構
- 結構類型的改進
- 內插字符串處理程序
- 指令
- 文件范圍的命名空間聲明
- 擴展屬性模式
- 對 Lambda 表達式的改進
- 可使用 內插字符串
- 記錄類型可密封
- 改進型明確賦值
- 在同一析構中可同時進行賦值和聲明
- 可在方法上使用 屬性
- CallerArgumentExpression 屬性
- 增強的 pragma
C# 11 (Visual Studio 2022, .Net 7.0)
主要功能特性
- 原始字符串字面量
注: 左引號之后、右引號之前的換行符不包括在最終內容中
string longMessage = """This is a long message.It has several lines.Some are indentedmore than others.Some should start at the first column.Some have "quoted text" in them.""";
- 泛型數學支持
- 泛型屬性
- UTF-8 字符串字面量
- 字符串內插表達式中的換行符
- 列表模式
- 文件本地類型
- 必需的成員
- 自動默認結構
- 常量 string 上的模式匹配 Span
- 擴展的 nameof 范圍
- 數值 IntPtr
- ref 字段和 scoped ref
- 改進了方法組向委托的轉換
- 警告波
PS. 從 .NET 6.0.200 SDK 或 Visual Studio 2022 版本 17.1 開始,可以試用 C# 中的預覽功能。
參考網頁?官網:C# 11.0 中的新增功能
C# 12 (Visual Studio 2022,.Net 8.0)
主構造函數
默認 Lambda 參數
任何類型的別名
內聯數組
偵聽器
參考:?官網鏈接
日志
- 2023/08/01 更新部分錯誤并優化文檔
- 2022/05/02 添加 11.0
參考資料
- Expression-bodied 成員(C# 編程指南), 微軟官方, 2017.
- VS2017十五項新功能體驗, Leo_wl, 2017.
- 帶你玩轉Visual Studio——VS2015的新功能和特性
- 詳解C#7.0新特性, CNXY, 2017-10.
- C# Version History, TutorialsTeacher.com, 2019.
- 文章鏈接