C#是一種通用的,類型安全的,面向對象的編程語言。有以下特色:html
(1)面向對象:c# 是面向對象的範例的一個豐富實現, 它包括封裝、繼承和多態性。C#面向對象的行爲包括:程序員
(2)類型安全:C#還容許經過dynamic關鍵字動態指定類型。 可是,C#仍然是一個主要的靜態類型語言。之因此是一種強類型的語言,是由於它的類型規則是很是嚴格的,例如,不可以使用一個float類型的參數去調用一個解釋int 類型的函數,除非顯式的把float轉換爲int ,這樣有助於防止編碼錯誤。shell
(3)內存管理:C#依賴運行時的自動內存管理,它的公共語言運行庫有一個垃圾回收器,在合適非時間回收再也不引用的對象所佔的空間,這就釋放了程序員手動釋放對象的內存。C#並無消除指針,它只是使大多數編程任務不須要使用指針,對於性能要求高的地方,仍是可使用指針的,可是隻容許在顯式標記爲不安全的代碼塊中使用。編程
(4)C#和CLR:C#是依賴runtime提供的內存管理和異常處理,CLR容許開發者使用不一樣的語言創建應用程序。C#是被編譯成託管代碼的幾種託管語言之一。託管代碼以中間語言或IL表示。CLR把IL轉換成機器的本地代碼,例如X86或X64,一般就在此以前執行,這被稱爲即時(Just-In-Time,JIT)編譯。 提早時間編譯也可用於改善大型程序集的啓動時間,或資源受限的設備。元數據的存在容許,程序集引用其餘程序集中的類型而不須要額外的文件。c#
(5)CRL和 .Net Framework的關係數組
.NET Framework由CLR和大量的庫組成;該類庫中包含核心類庫(也就是基礎類庫BCL)和應用類庫,應用類庫又依賴核心類庫安全
婆婆媽媽說了這麼多,我相信你們都知道,好了,下面咱們經過代碼來看看C#7.0到底有哪些讓你拍手叫好的地方。異步
(1)數字字面量的提高:async
C#7中的數字文字能夠包含下劃線以提升可讀性,這些被稱爲數字分隔符,並被編譯器忽略。編程語言
代碼以下:
運行結果:
注意:二進制文字能夠用0b前綴指定。
因此見到這種寫法你不要驚訝,只是爲了提升可讀性。
(2)Out variables and discards(接收out變量和丟棄out變量)
代碼:
之前咱們的寫法:
如今C#7.0中能夠這樣寫:
咱們不須要在外面先定義好要接收值的變量,而是直接在裏面寫,是否是代碼更簡潔,另一個有趣的地方是,當一個方法要返回多個值的時候,咱們可使用 out _,來選擇性的接收返回來的值,在上面圖中的代碼中,方法SomeBigMethod返回四個值,可是咱們在接收它返回來的值時,可使用out _不接收返回來的值,而使用out int x,來接收返回來的值,是否是很靈活。
代碼運行結果以下:
ILSpy結果:
// Methods .method private hidebysig static void Main ( string[] args ) cil managed { // Method begins at RVA 0x2050 // Code size 49 (0x31) .maxstack 4 .entrypoint .locals init ( [0] int32, [1] bool, [2] int32, [3] int32, [4] int32, [5] int32 ) // (no C# code) IL_0000: nop // bool successful = int.TryParse("123", out result); IL_0001: ldstr "123" IL_0006: ldloca.s 0 IL_0008: call bool [System.Runtime]System.Int32::TryParse(string, int32&) IL_000d: stloc.1 // SomeBigMethod(out int _, out int _, out int x, out int _); IL_000e: ldloca.s 3 IL_0010: ldloca.s 4 IL_0012: ldloca.s 2 IL_0014: ldloca.s 5 IL_0016: call void ConsoleApp1.Program::SomeBigMethod(int32&, int32&, int32&, int32&) // (no C# code) IL_001b: nop // Console.WriteLine(x); IL_001c: ldloc.2 IL_001d: call void [System.Console]System.Console::WriteLine(int32) // (no C# code) IL_0022: nop // Console.WriteLine(result); IL_0023: ldloc.0 IL_0024: call void [System.Console]System.Console::WriteLine(int32) // (no C# code) IL_0029: nop // Console.ReadKey(); IL_002a: call valuetype [System.Console]System.ConsoleKeyInfo [System.Console]System.Console::ReadKey() IL_002f: pop // (no C# code) IL_0030: ret } // end of method Program::Main
(3)Patterns
做用:你可使用is運算符來引入一個變量,這個變量被稱爲模式變量。不明白,看個例子就明白了。
代碼以下:
解析:x is string s 的做用是:若是x 能夠被轉換爲string 轉換後的值賦值給了s ,因此輸出的結果就是字符串的長度。
其中switch的聲明也支持這種模式,並且還可使用when子句指定條件,代碼以下:
運行結果:
解析:Foo2(9)傳遞過來的是9,是int 類型,因此就進入到第一個case 子句中,因此最終輸出的結果就是:It is an int !,這個解釋給零分,下面咱們經過ILSpy看看這種語法糖究竟是什麼東東,以下圖所示:
我就不解釋了,你們一看就明白,是否是想拍下大腿,TM原來就這麼簡單!!!
(4)本地方法(Local methods)
做用:A local method is a method declared inside another function。這裏我給出英文,由於這種方式給出是最準確的,中文翻譯出來就TM看不懂了。
運行結果:
解析: 定義了一個本地方法,返回值類型是int 傳入的參數是value ,返回值是:value*value*value+i
Cube(2),調用傳入值2 ,因此最終計算出來的值爲 2*2*2+9=17
注意:本地方法僅對包含函數可見,而且可使用包含該本地方法的變量。
ILSpy反編譯的結果:
能夠看出在調用Cube(2),最終被編譯成Cube(2,ref xx)這樣一個方法,但看不到 <WriteCubes>g__Cube|3_0方法的內部實現。
(5)c# 6 介紹了方法的 "fat-箭頭" 語法, 能夠用在只讀、屬性、運算符和索引器。c# 7 將此擴展到構造函數、讀/寫屬性、終結器
代碼:
ILSPy代碼結果:
(6)對於 c# 7, 可能最顯著的改進是顯式元組支持
做用:元組提供了一種簡單的方法來存儲一組相關值
代碼:
運行結果:
解析: var bob = ("Bob", 23);定義了一個元組,可使用bob.Item1來訪問第一個參數,可使用bob.Item2來訪問第二參數,但問題來了,爲何能夠這樣來訪問???
ILSpy結果:
能夠看到,元組實際上是一個ValueTuple<,>的泛型類型,其中string int 是有你的值的類型決定的,那爲何可使用Item1和Item2來訪問對應的值呢?
首先Item1和Item2是人家 ValueTuple<T1, T2> 中定義的,那爲何我訪問Item1就是"Bob",那是由於在構造函數中,把"Bob"賦值給了Item1,因此明白了吧。
另外能夠看出元組是一個結構體,屬於值類型的。講到這裏尚未講完元組的點,因爲編譯器的魔力, 元組元素能夠被命名爲下面的形式:
ILSpy結果:
藉助於元組,函數能夠返回多個參數,而不須要藉助於out 參數:
運行結果:
ILSpy結果:
注意:元組隱含地支持反解析模式, 所以它們能夠很容易地被分解成單個變量。咱們能夠重寫前面的主方法使 GetFilePosition 返回的元組被分配給兩個局部變量:row和cloum:
運行結果:
ILSPy結果:(結果和上面的同樣)
好了,元組就講到這裏,接下讓咱們看看如何拋出異常。
(7)拋出異常
功能:在C#7以前,throw老是要被聲明,如今它能夠做爲一個表達式出如今一個函數 體中,並且也能夠出如今三元表達式中。
ILSpy結果:
(8)字符串的插值
直接上代碼:
若是要多行顯示,能夠這樣寫:
注意:$符必定要在@符號以前。
ILSpy結果:
簡單我就很少說了,繼續下面的知識點。
(9)異常篩選器(Exception filters)
做用:容許你在catch中應用一個條件。
(10)引用本地變量Ref Locals
做用:C#7.0中引入了一個極爲重要的點,藉此,你能夠定義一個本地變量,這個變量引用一個數組中的元素或者對象中的字段。
代碼:
注意:Ref Locals 必須是數組中的一個元素、字段、或者本地變量,不能是屬性。它一般與 ref returns 一塊兒使用。
運行結果:
解析:ref int age 標註這個變量時就是一個引用類型的變量。
(11)Ref Returns
做用:你能夠在一個方法中返回一個 ref local,這種方式被叫作ref return
代碼:
運行結果:
解析:private static ref int GetX() 實際上是一個 返回值爲int32&(就是一個標記了內存指針的INT32類型)的方法,也就是返回一個地址,這樣我再修改值後其實就是修改的x的值。
ILSpy結果:
注意:ldsflda int32 :是把一個靜態字段x的地址壓入到棧中,ret,而後返回,在Main方法中,調用上面的方法後,從棧頂把值取出來,存儲到本地變量列表中索引位置0裏面。
而後取本地變量中索引位置爲0的值,並壓入棧中,注意重點來了,stind.i4 是把 ldc.i4.s 9 值 的地址存儲下來,這樣就改變了x的值。因此這個int32&其實就是一個變量的地址,也就是咱們一般所說的指針。
好了講到這裏基本上C#7.0新增的功能就講的差很少了,後續我會繼續補充C#7.0新的知識點,但願對你有幫助!謝謝。
最後,歡迎你們加入到個人C#+.Net Core英文書籍翻譯羣,我會不按期經過博客更新翻譯的英文資料,但願獲得最新的C#知識,同時對你我也有所提升。
C# 7.1
2017年8月c# 7.1 發佈了 , 做爲Visual Studio 2017(15.3 版 ) 更新的一部分。不一樣於新語言的發佈,這一次發佈的新功能不會由於你更新了Visual Studio 2017而啓用,即不在現有項目中,也不在建立的新項目中出現。
若是咱們想嘗試C#7.1的新特性,生成時的報錯信息會提示咱們升級語言的版本:
注意:若是你已經保證Visual Studio 2017(15.3 版 ) 是最新版本的話,咱們能夠經過下面的方法來更改默認C#的版本,在控制檯項目右鍵,選擇「 屬性」,以下圖:
注意這裏要強調一點:默認狀況下C#7.1是沒有被選中的,這是爲了開發團隊可以更好的控制使用次要版本的語言,若是新的語言特性自動可用,這將強制團隊一開始用這些新特性的時候,就要立馬更新IDE,當一個新特性第一次被應用在項目中,它是不會被編譯的。咱們所選的語言版本是被保存在項目中的,是一個特定的項目,並且須要特定的配置。所以當咱們再項目屬性中改變語言的版本時,你要確保它對全部的配置都適用。咱們能夠以下配置:
選擇全部配置。若是你僅僅選擇了語言的版本和Debug配置,那麼會形成在release下是生產失敗。
對於某些語言功能, VS2017還有一個可用的代碼修復功能 ,它將更改語言版本到
7.1 或最新的次要版本,在設置了all configurations配置的狀況下。
好了,下面讓咱們利用ILSpy繼續探索C#7.1的新特性。
(1)Async Main
在C#7.0中就有考慮過,支持異步的Main函數,可是被擱置了直到C#7.1纔出現,它的出現可使控制檯應用程序中的Main函數,可使用async 和 await 語法。在C#7.1以前,在 c# 7.1 以前, 主方法做爲程序入口點支持如下內容:
public static void Main();
public static int Main();
public static void Main(string[] args);
public static int Main(string[] args);
當一個方法的內部調用另一個異步方法的時候,使用了await時,這個方法就要使用async ,也就是說兩個須要同時出現,雖然變通方法是編寫多行樣板代碼,可是這樣的模式依賴於對方法的非正常使用,難於理解。例如:
static void Main(string[] args)
{
MainAsync(args).GetAwaiter().GetResult();
}
static async Task MainAsync(string[] args)
{
// asynchronous code
}
在C#7.1中對於異步的Main方法支持額外的簽名:
public static Task Main();
public static Task Main();
public static Task Main(string[] args);
public static Task Main(string[] args);
當使用上面這些簽名時,能夠在異步的方法中直接寫async,編譯器將會生產對應的樣板代碼,使他們工做。
代碼:
(2)Default Literal Expressions
做用:默認值表達式可用於返回給定類型的默認值。
C#7.1以前的寫法:
特別是在用泛型類型時, 咱們不知道返回什麼樣的值,能夠這樣作:
C#7.1中的寫法:
(3)Inferred Tuple Element Names(推斷元組元素名稱)
元組首先是在C#7.0中引入的,C#7.1進行了輕微的改動,當在建立元組的時候必須顯示的指定名稱,不然元素只能經過默認名稱 Item一、Item2 等:
在 c# 7.1 中, 能夠從用於構造元組的變量的名稱推斷出元組名稱。代碼以下:
ILSpy結果:(不解釋了)
(4)Generic Pattern Matching
做用:c# 7.0 中最重要的新功能之一是使用 "is" 關鍵字進行模式匹配和switch語句,類型模式容許咱們基於值類型進行分支,可是這對泛型的類型不起做用,下面的代碼在C#7.0中是不能編譯成功的。
void Attack<T>(T weapon, IEnemy enemy) where T : IWeapon
{
switch (weapon)
{
case Sword sword:
// process sword attack
break;
case Bow bow:
// process bow attack
break;
}
}
c# 7.1 擴展類型模式以支持泛型類型, 從而使代碼有效。
C#7.2
語言的發展並無隨着 c# 7.1 的發佈而中止。該團隊已經在工做下一次要版本7.2具體的發佈日期並無宣佈,儘管這些他們公開談過,可是這些新的功能並非很好用。目前爲C#7.2計劃的幾種語言新功能,仍然會受到改進,其中有些可能會推遲到更高版本,還有可能會添加新的功能。好了接下來讓咱們繼續看看C#7.2中有哪些新的功能。
(1)基本說明符後的數字分隔符
C#7.0
代碼:
C#7.2 容許使用分隔符(0x_ 0b_)
代碼:
(2)Non-trailing Named Arguments
命名參數是在C#4.0中添加進來的,它們主要是容許可選參數在調用方法時能夠跳過某些參數, 但對於後面的全部參數,必須使用命名參數, 以便編譯器可以匹配它們。
代碼:
若是一個參數不是可選參數,參數仍然可使用命名參數以提升代碼的可讀性,而且使用命名參數前提下,能夠改變參入參數的位置。
代碼:
可是, c# 還不容許位置參數在同一個方法調用中跟隨命名參數:
代碼:
C#7.2
可是出於代碼的可讀性,最好仍是使用下面這種方式(別讓編譯器寵壞你):
(3)Conditional Ref Operator(條件Ref運算符)
代碼:
C#8.0(簡單瞭解便可,知道有這個點就好了)
(1)Recursive Patterns(遞歸模式)
在前在C#7.0中也講到了模式的問題,在C#8.0中有進一步的支持,遞歸模式是計劃被添加到其中的一種模式,他們將會容許部分數據匹配子模式。
(2)Default Interface Methods(默認的接口方法)
(3)Nullable Reference Types(可空的引用類型)
參考書籍:《C 7.0 in a Nutshell 7th Edition》
關於C#6.0的能夠參考這篇文章:
敏捷的水:http://www.cnblogs.com/cnblogsfans/p/5086292.html
做者:郭崢
出處:http://www.cnblogs.com/runningsmallguo/
本文版權歸做者和博客園共有,歡迎轉載,但未經做者贊成必須保留此段聲明,且在文章頁面明顯位置給出原文連接。