C# 語言歷史版本特性(C# 1.0到C# 8.0彙總
C# 語言歷史版本特性(C# 1.0到C# 8.0彙總)
歷史版本
C#作為微軟2000年以後.NET平臺開發的當家語言,發展至今具有17年的歷史,語言本身具有豐富的特性,微軟對其更新支援也十分支援。微軟將C#提交給標準組織ECMA,C# 5.0目前是ECMA釋出的最新規範,C# 6.0還是草案階段,C# 7.1是微軟當前提供的最新規範。
這裡僅僅列個提綱,由於C# 5.0是具有ECMA標準規範的版本,所以選擇C# 5.0作為主要版本學習,並專題學習C# 6.0,7.0版本新特性。
C#語言規範GitHub庫參見:https://github.com/dotnet/csharplang
C#語言路線圖及開發中的特性參見:
語言版本 | 釋出時間 | .NET Framework要求 | Visual Studio版本 |
---|---|---|---|
C# 1.0 | 2002.1 | .NET Framework 1.0 | Visual Studio .NET 2002 |
C# 1.1\1.2 | 2003.4 | .NET Framework 1.1 | Visual Studio .NET 2003 |
C# 2.0 | 2005.11 | .NET Framework 2.0 | Visual Studio 2005 |
C# 3.0 | 2007.11 | .NET Framework 2.0\3.0\3.5 | Visual Studio 2008 |
C# 4.0 | 2010.4 | .NET Framework 4.0 | Visual Studio 2010 |
C# 5.0 | 2012.8 | .NET Framework 4.5 | Visual Studio 2012\2013 |
C# 6.0 | 2015.7 | .NET Framework 4.6 | Visual Studio 2015 |
C# 7.0 | 2017.3 | .NET Framework 4.6.2 | Visual Studio 2017 |
C# 7.1 | 2017.6 | .NET Framework | Visual Studio 2017 v15.3預覽版 |
C# 8.0 | 待發布 | .NET Framework 4.7.1 | Visual Studio 2017 v15.7 |
C# 1.0 特性
第1個版本,程式語言最基礎的特性。
- Classes:面向物件特性,支援類型別
- Structs:結構
- Interfaces:介面
- Events:事件
- Properties:屬性,類的成員,提供訪問欄位的靈活方法
- Delegates:委託,一種引用型別,表示對具有特定引數列表和返回型別的方法的引用
- Expressions,Statements,Operators:表示式、語句、操作符
- Attributes:特性,為程式程式碼新增元資料或宣告性資訊,執行時,通過反射可以訪問特性資訊
- Literals:字面值(或理解為常量值),區別常量,常量是和變數相對的
C# 2特性 (VS 2005)
- Generics:泛型
- Partial types:分部型別,可以將類、結構、介面等型別定義拆分到多個檔案中
- Anonymous methods:匿名方法
- Iterators:迭代器
- Nullable types:可以為Null的型別,該類可以是其它值或者null
- Getter/setter separate accessibility:屬性訪問控制
- Method group conversions (delegates):方法組轉換,可以將宣告委託代表一組方法,隱式呼叫
- Co- and Contra-variance for delegates and interfaces:委託、介面的協變和逆變
- Static classes:靜態類
- Delegate inference:委託推斷,允許將方法名直接賦給委託變數
C# 3特性 (VS 2008)
- Implicitly typed local variables:
- Object and collection initializers:物件和集合初始化器
- Auto-Implemented properties:自動屬性,自動生成屬性方法,宣告更簡潔
- Anonymous types:匿名型別
- Extension methods:擴充套件方法
- Query expressions:查詢表示式
- Lambda expression:Lambda表示式
- Expression trees:表示式樹,以樹形資料結構表示程式碼,是一種新資料型別
- Partial methods:部分方法
C# 4特性 (VS 2010)
- Dynamic binding:動態繫結
- Named and optional arguments:命名引數和可選引數
- Generic co- and contravariance:泛型的協變和逆變
- Embedded interop types (“NoPIA”):開啟嵌入型別資訊,增加引用COM元件程式的中立性
C# 5特性 (VS 2012)
- Asynchronous methods:非同步方法
- Caller info attributes:呼叫方資訊特性,呼叫時訪問呼叫者的資訊
C# 6特徵 (VS 2015)
- Compiler-as-a-service (Roslyn)
- Import of static type members into namespace:支援僅匯入類中的靜態成員
- Exception filters:異常過濾器
- Await in catch/finally blocks:支援在catch/finally語句塊使用await語句
- Auto property initializers:自動屬性初始化
- Default values for getter-only properties:設定只讀屬性的預設值
- Expression-bodied members:支援以表示式為主體的成員方法和只讀屬性
- Null propagator (null-conditional operator, succinct null checking):Null條件操作符
- String interpolation:字串插值,產生特定格式字串的新方法
- nameof operator:nameof操作符,返回方法、屬性、變數的名稱
- Dictionary initializer:字典初始化
C# 7 特徵 (Visual Studio 2017)
- Out variables:out變數直接宣告,例如可以out in parameter
- Pattern matching:模式匹配,根據物件型別或者其它屬性實現方法派發
- Tuples:元組
- Deconstruction:元組解析
- Discards:沒有命名的變數,只是佔位,後面程式碼不需要使用其值
- Local Functions:區域性函式
- Binary Literals:二進位制字面量
- Digit Separators:數字分隔符
- Ref returns and locals:引用返回值和區域性變數
- Generalized async return types:async中使用泛型返回型別
- More expression-bodied members:允許構造器、解析器、屬性可以使用表示式作為body
- Throw expressions:Throw可以在表示式中使用
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# 8.0 特徵 (Visual Studio 2017 version 15.7)
- Default Interface Methods 預設介面實現
- Nullable reference type NullableReferenceTypes 非空和可控的資料型別
- Recursive patterns 遞迴模式
- Async streams 非同步資料流
- Caller expression attribute 呼叫方法表示式屬性
- Target-typed new
- Generic attributes 通用屬性
- Ranges
- Default in deconstruction
- Relax ordering of ref and partial modifiers
標籤:C#新特性,C#8.0,C#版本與net framework版本對照,C#歷史版本
C#5.0版本
像C#4.0版本一樣,C#5.0版本中沒有太多功能 - 但是其中一個功能非常龐大。
- 非同步/等待
- CallerInfoAttributes
當C#5.0釋出時,它實際上改變了C#開發人員編寫非同步程式碼的方式。雖然直到今天仍然有很多困惑,但我在這裡向您保證,這比大多數人想象的要簡單得多。這是C#的一個重大飛躍 - 它引入了一個語言級別的非同步模型,它極大地賦予了開發人員編寫外觀和感覺同步(或者至少是連續的)的“非同步”程式碼。
非同步程式設計在處理I/O繫結工作負載(如與資料庫,網路,檔案系統等進行互動)時非常強大。非同步程式設計通過使用非阻塞方法幫助處理吞吐量。這種方法使用了一個透明的非同步狀態機中的掛點和相應的延續。
同樣,如果CPU負載計算的工作量很大,則可能需要考慮非同步執行此項工作。這將有助於使用者體驗,因為UI執行緒不會被阻塞,而是可以自由地響應其他UI互動。
編者注:這裡有一些關於C#非同步程式設計的最佳實踐,使用Async Await.
在C#5.0中,當語言添加了兩個新的關鍵字async和await時,非同步程式設計被簡化了。這些關鍵字適用於Task。下表將作為參考:
Task表示非同步操作。操作可以通過Task返回值,也可以通過Task返回void。當您使用async關鍵字修飾Task返回方法時,它使方法主體可以使用await關鍵字。當您請求await關鍵字的返回值時,控制流將返回給呼叫者,並且在方法的那個點執行暫停。當await的操作完成後,在同一點上恢復執行。部分程式碼如下!
-
class
IOBoundAsyncExample
-
{
-
-
private
const
string Url =
"http://api.icndb.com/jokes/random?limitTo=[nerdy]";
-
-
internal async Task GetJokeAsync()
-
{
-
using (
var client =
new HttpClient())
-
{
-
var response =
await client.GetStringAsync(Url);
-
var result = JsonConvert.DeserializeObject(response);
-
-
return result.Value.Joke;
-
}
-
}
-
}
-
public
class
Result
-
{
-
[
JsonProperty("type")]
public
string Type {
get;
set; }
-
[
JsonProperty("value")]
public Value Value {
get;
set; }
-
}
-
-
public
class
Value
-
{
-
[
JsonProperty("id")]
public
int Id {
get;
set; }
-
[
JsonProperty("joke")]
public
string Joke {
get;
set; }
-
}
我們用一個名為GetJokeAsync的方法定義一個簡單的類。該方法是返回Task,這意味著我們的GetJokeAsync方法最終會給您一個字串,或者可能出錯。
該方法使用async關鍵字進行修飾,該關鍵字允許使用等待關鍵字。我們例項化並使用一個HttpClient物件。然後我們呼叫GetStringAsync函式,它接受一個字串url並返回一個Task 。我們等待從GetStringAsync呼叫返回的Task。
當響應已經準備好時,就會繼續發生並控制從我們曾經掛起的位置恢復。然後,我們將JSON反序列化到Result類的例項中,並返回Joke屬性。
一些我最喜歡的成果
- 查克·諾里斯(Chuck Norris)可以用單一的斷言來測試整個應用程式。
- 查克·諾里斯(Chuck Norris)可以編譯語法錯誤。
- 專案經理永遠不會要求查克·諾里斯(Chuck Norris)做出估計。
歡鬧隨之而來!我們瞭解了C#5.0的驚人的非同步程式設計模型。
C#6.0版本
C#6.0的推出有很多很大的進步,很難選擇我最喜歡的功能。
- 字典初始化
- 異常過濾器
- 在屬性裡使用Lambda表示式
- nameof表示式
- 空值運算子
- 自動屬性初始化
- 靜態匯入
- 字串嵌入值
我把範圍縮小到三個突出特點:空值運算子,字串嵌入值和nameof表示式。
雖然nameof表示式很棒,我幾乎每次都用它來編寫程式碼,但其他兩個特性更有影響力。這讓我在字串嵌入值和空值運算子之間做出決定,這是相當困難的。我決定我最喜歡的是字串嵌入值,這就是為什麼。
空值運算子是偉大的,它允許我寫較少的詳細程式碼,但它不一定能防止我的程式碼中的錯誤。但是,使用字串嵌入值可以防止執行時錯誤 - 這是我的書中的一個勝利。
使用$符號啟動字串文字時,將啟用C#中的字串嵌入值語法。這指示C#編譯器打算用各種C#變數,邏輯或表示式來插入此字串。這是手動字串連線甚至是string.Format方法的一個主要升級。考慮以下:
-
class
Person
-
{
-
public
string FirstName {
get;
set; }
-
public
string LastName {
get;
set; }
-
-
public override string ToString()
-
=>
string.Format(
"{0} {1}", FirstName);
-
}
我們有一個簡單的Person類,具有兩個名稱屬性,用於名字和姓氏。我們重寫ToString方法並使用string.Format。問題是,編譯時,由於開發人員顯然希望將姓氏也作為結果字串的一部分,因此很容易出錯,這一點在“{0} {1} ”引數中很明顯。同樣,開發人員可以很容易地交換名稱或正確提供兩個名稱引數,但混亂的格式文字只包括第一個索引,等等...現在我們可以考慮使用字串嵌入值。
-
class
Person
-
{
-
public
string FirstName {
get;
set; } =
"David";
-
public
string LastName {
get;
set; } =
"Pine";
-
public DateTime DateOfBirth {
get;
set; } =
new DateTime(
1984,
7,
7);
-
-
public override string ToString()
-
=>
$"{FirstName} {LastName} (Born {DateOfBirth:MMMM dd, yyyy})";
-
}
我冒昧新增DateOfBirth屬性和一些預設的屬性值。另外,我們現在在我們的ToString方法的覆蓋中使用字串嵌入值。作為一名開發人員,犯上述錯誤要困難得多。最後,我也可以在插值表示式中進行格式化。注意第三次嵌入值,DateOfBirth是一個DateTime - 因此我們可以使用您已經習慣的所有標準格式。只需使用:運算子來分隔變數和格式。
示例輸出
· David Pine (Born July 7, 1984)
編輯注:有關C#6.0新特性的詳細內容,請閱讀www.dotnetcurry.com/csharp/1042/csharp-6-new-features
C#7.0版本
從所有整合到 C# 7.0的特性中。
- 更多的函式成員的表示式體
- 區域性函式
- Out變數
- 模式匹配
- 區域性變數和引用返回
- 元組和解構
我結束了模式匹配,元組和Out變數之間的爭論。我最終選擇了Out變數,這是為什麼。
模式匹配但是我真的不經常使用它,至少現在還沒有。也許以後我會更多地使用它,但是對於我迄今為止編寫的所有c#程式碼,沒有太多地方可以利用它。同樣,這是一個很棒的功能,我確實看到了它的位置 - 只是在C#7.0中這不是我最喜歡的。
元組也是一個很好的補充。元組是語言的重要組成部分,成為一流的公民是非常棒的。我會說,“寫tem1,.Item2,.Item3等...的日子已經過去了,但這並不一定是正確的。反序列化失去了元組的名稱,使得這個公共API不那麼有價值
我也不喜歡ValueTuple型別是可變的這一事實。我只是不明白設計者的決定。我希望有人能給我解釋一下,但感覺有點像疏忽。因此,我得到了選擇out變數的特性。
自從C#版本1.0以來,try-parse模式已經在各種值型別中出現了。模式如下:
-
public boolean TryParse(string value, out DateTime date)
-
{
-
// 為了簡便起見,我們省略了.....
-
}
該函式返回一個布林值,指示給定的字串值是否能夠被解析。如果為true,則將分析的值分配給生成的輸出引數date。它的使用如下:
-
DateTime
date;
-
if (DateTime.TryParse(someDateString, out
date))
-
{
-
//
date現在是解析值
-
}
-
else
-
{
-
//
date是DateTime.MinValue,預設值
-
}
這種模式是有用的,但有點麻煩。有時,不管解析是否成功,開發人員都會採取相同的操作過程。有時使用預設值是可以的。C#7.0中的out變數使得這個更復雜,不過在我看來不那麼複雜。
示例如下:
-
if (DateTime.TryParse(someDateString,
out
var date))
-
{
-
// date現在是解析值
-
}
-
else
-
{
-
// date是DateTime.MinValue,預設值
-
}
現在我們移除了if語句塊的外部宣告,並把宣告作為引數本身的一部分。使用var是合法的,因為型別是已知的。最後,date變數的範圍沒有改變。它從內聯宣告洩漏到if塊的頂部。
你可能會問自己:“為什麼這是他最喜歡的功能之一?”.....這種感覺真的沒有什麼變化。
但是這改變了一切!
它使我們的C#更具有表現力。每個人都喜歡擴充套件方法,對 - 請考慮以下幾點:
-
public
static
class
StringExtensions
-
{
-
private delegate bool TryParseDelegate(string s, out T result);
-
-
private static T To(string value, TryParseDelegate parse)
-
=> parse(
value,
out T result) ? result :
default;
-
-
public static int ToInt32(this string value)
-
=> To(
value,
int.TryParse);
-
-
public static DateTime ToDateTime(this string value)
-
=> To(
value, DateTime.TryParse);
-
-
public static IPAddress ToIPAddress(this string value)
-
=> To(
value, IPAddress.TryParse);
-
-
public static TimeSpan ToTimeSpan(this string value)
-
=> To(
value, TimeSpan.TryParse);
-
}
這個擴充套件方法類很簡潔,表達能力強。在定義了遵循try-parse模式的私有委託之後,我們可以編寫一個泛型複合函式,它需要一個泛型型別的引數、要解析的字串值和TryParseDelegate。現在我們可以安全地依賴這些擴充套件方法,考慮以下幾點::
-
public
class Program
-
{
-
public
static
void Main(
string[] args)
-
{
-
var str =
-
string.Join(
-
"",
-
new[] {
"James",
"Bond",
" +7 " }.Select(s => s.ToInt32()));
-
-
Console.WriteLine(str);
// 列印 "007"
-
}
-
}
編輯注:要了解C#7的所有新功能,請檢視本教程www.dotnetcurry.com/csharp/1286/csharp-7-new-expected-features
結論
這篇文章對我個人而言頗具挑戰性。我喜歡C#的許多特性,因此每次釋出只收集一個最喜歡的內容是非常困難的。
每個較新版本的C#都包含了強大而有影響力的功能。C#語言團隊以無數的方式進行創新 - 其中之一就是引入點發布。在撰寫本文時,C# 7.1和 7.2已正式發貨。作為C#開發人員,我們生活在一個激動人心的語言時代!
然而,對我來說,對所有這些特性進行分類是相當有見地的;因為它幫助我們瞭解了什麼是實際的,最影響我的日常發展。一如既往,努力成為一個務實的開發者!並不是語言中所有可用的特性都是當前任務所必需的,但瞭解什麼是可用的,這一點很重要。
當我們期待C#8的建議和原型時,我對C#的未來感到興奮。它看起來確實很有希望,而且語言正在積極地試圖緩解“價值億萬美金的錯誤”。
歡迎轉載,轉載請註明翻譯原文出處(本文章),原文出處(原部落格地址),然後謝謝觀看
如果覺得我的翻譯對您有幫助,請點選推薦支援:)
C# 6.0+VS2015:win8/win10;空值運算子,字串嵌入值和nameof表示式。
C# 7.0+VS2018:win10元組和解構.
vs2018(c#8.0):正在開發中。