使用ILSpy探索C#7.0新增功能點

來源:互聯網
上載者:User
第一部分:

C#是一種通用的,型別安全的,物件導向的程式設計語言。有如下特點:

(1)物件導向:c# 是物件導向的範例的一個豐富實現, 它包括封裝、繼承和多態性。C#物件導向的行為包括:

統一的類型系統

類與介面

屬性、方法、事件

(2)型別安全:C#還允許通過dynamic關鍵字動態指定類型。 但是,C#仍然是一個主要的靜態類型語言。之所以是一種強型別的語言,是因為它的類型規則是非常嚴格的,例如,不能夠使用一個float類型的參數去調用一個解釋int 類型的函數,除非顯式的把float轉換為int ,這樣有助於防止編碼錯誤。

(3)記憶體管理:C#依賴運行時的自動記憶體管理,它的公用語言運行庫有一個記憶體回收行程,在合適非時間回收不再引用的對象所佔的空間,這就釋放了程式員手動釋放對象的記憶體。C#並沒有消除指標,它只是使大多數編程任務不需要使用指標,對於效能要求高的地方,還是可以使用指標的,但是只允許在顯式標記為不安全的代碼塊中使用。

(4)C#和CLR:C#是依賴runtime提供的記憶體管理和異常處理,CLR允許開發人員使用不同的語言建立應用程式。C#是被編譯成Managed 程式碼的幾種託管語言之一。Managed 程式碼以中繼語言或IL表示。CLR把IL轉換成機器的本地代碼,例如X86或X64,通常就在此之前執行,這被稱為即時(Just-In-Time,JIT)編譯。 提前時間編譯也可用於改善大型程式集的啟動時間,或資源受限的裝置。中繼資料的存在允許,程式集引用其他程式集中的類型而不需要額外的檔案。

(5)CRL和 .Net Framework的關係

.NET Framework由CLR和大量的庫組成;該類庫中包含核心類庫(也就是基礎類庫BCL)和應用類庫,應用類庫又依賴核心類庫

 

婆婆媽媽說了這麼多,我相信大家都知道,好了,下面我們通過代碼來看看C#7.0到底有哪些讓你拍手叫好的地方。 第二部分:C#7.0新增的功能

(1)數字字面量的提升:

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.0 in a Nutshell 7th Edition》

相關文章:

C# 這些年來受歡迎的特性

C# 7編程模式與實踐

C# 7.1、7.2特性追蹤

C# 7.2和8.0路線圖

原文地址:https://www.cnblogs.com/runningsmallguo/p/8972678.html

 

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.