C# 6.0語法新特性體驗(二)


之前我在文章通過Roslyn體驗C# 6.0的新語法中介紹了一些C# 6.0的語法特性,現在隨着Visual Studio 14 CTP3的發布,又陸續可以體驗一些新的特性了,這里簡單的介紹一下之前沒有介紹的新語法。

屬性表達式(Property Expressions)

我們常常會在類中寫一些通過函數生成的只讀屬性:

    class Point
    {
        public int X { get; set; }
        public int Y { get; set; }

        public Point(int x, int y)
        {
            this.X = x;
            this.Y = y;
        }

        
public double Distance
        {
            get { return Math.Sqrt((X * X) + (Y * Y)); }
        }

        
public Point Move(int dx, int dy)
        {
            return new Point(X + dx, Y + dy);
        }
    }

現在,可以利用一個Lambda表達式簡化這一過程:

        public double Distance => Math.Sqrt((X * X) + (Y * Y));

 

函數表達式(Method Expressions)

函數表達式和屬性表達式比較類似,使得我們可以通過Lambda表達式簡化成員函數。還是以上面的Point為例,Move函數可以簡化如下

        public Point Move(int dx, int dy) => new Point(X + dx, Y + dy);

最后,再總結前文介紹的幾個新特性來一起來簡化Point類:

    class Point(int x, int y)
    {
        public int X { get; set; } = x;
        public int Y { get; set; } = y;

        public double Distance => Math.Sqrt((X * X) + (Y * Y));

        public Point Move(int dx, int dy) => new Point(X + dx, Y + dy);
    }

  

NULL檢查運算符(Monadic null checking)

這個是我非常喜歡的一個語法,例如我們要獲取一個Point序列的第一個點的X坐標,第一感覺會這么寫:

    int firstX = points.First().X;

但是,老鳥會告訴你,這兒沒有進行NULL檢查,正確的版本是這樣的:

    int? firstX = null;
    if (points != null)
    {
        var first = points.FirstOrDefault();
        if (first != null)
            firstX = first.X;
    }

正確倒是正確了,代碼取變得難讀多了。現在,在C# 6.0中,引入了一個 ?. 的運算符,前面的代碼可以改成如下形式:

    int? firstX = points?.FirstOrDefault()?.X;

從這個例子中我們也可以看出它的基本用法:如果對象為NULL,則不進行后面的獲取成員的運算,直接返回NULL

需要注意的是,由於"?."運算符返回的可以是NULL,當返回的成員類型是struct類型的時候,"?."和"."運算符的返回值類型是不一樣的。

    Point p = new Point(3, 2);

    Console.WriteLine(p.X.GetType() == typeof(int));        //true
    Console.WriteLine(p?.X.GetType() == typeof(int?));        //true

另外,除了"?."運算符外,還有一個"?[]"運算符,以使得我們可以寫出如下表達式:

    int? first = customers?[0].Orders.Count();

 

nameof表達式(Nameof expressions)

我們常常在反射或類似的技術中以字符串的形式使用屬性的名稱,拋開拼寫錯誤不談,當我們進行重構而修改屬性名稱的時候,由於字符串類型的屬性得不到編譯器檢查,修改相應的字符串屬性名稱是一件非常令人頭痛的事情,現在有了nameof,再也不用擔心拼錯屬性名稱了。

nameof運算符可以作用於變量、函數、類以及名字空間中,用於返回返回其名稱,例如:

    static void Main(string[] args)
    {
        Console.WriteLine(nameof(Main));        //
輸出 "Main"
    }

當其參數是由"."運算符拼接起來的時候,只返回最后的名稱,例如:

    Console.WriteLine(nameof(ConsoleApplication1.Program));        //輸出 "Program"

這個也可以理解,因為ConsoleApplication1.ProgramProgram本身就是等價的。

需要注意的是,由於C#允許函數重載,因此是存在同名函數的,例如:

    static void foo() { }
    static void foo(int x) { }

這樣就存在如下兩個問題:

  1. 轉到定義應該跳到那個函數?
  2. 當對其中的某個函數重命名,另一個函數維持原名稱的時候, 使用nameof的地方是否也需要變化?

這兩個問題只是體現在VisualStudio上,並不是語法的歧義,也不影響運行結果。在CodePlex中也有專門的文章討論它,目前的處理方式是:

  1. 轉到定義應該跳到那個函數?     (誰先定義轉到誰)
  2. 當對其中的某個函數重命名,另一個函數維持原名稱的時候, 使用nameof的地方是否也需要變化? (重命名函數不重命名nameof,其它的類型如屬性等重命名會一起變化)

 

catch和finally語句塊中支持await

在C# 5.0中引入了await運算符,可以方便我們執行異步運算。當時其並不能在catch和finally中使用,讓人有點意猶未盡的感覺。在C# 6.0放開了這一限制,使用更加方便了。

    try
    {
        res = await Resource.OpenAsync(…);
    }
    catch (ResourceException e)
    {
        await Resource.LogAsync(res, e);    //
現在支持了
    }
    finally
    {
        if (res != null) await res.CloseAsync(); //
現在也支持了
    }

 

catch支持篩選條件了

catch支持篩選條件也是呼聲比較高的特性之一,現在終於可以省得重新再拋一次了

    try
    {
        foo();
    }
    catch (Exception e ) if (e.HResult == 0x800000C)
    {
        //do something
    }

 

其它未支持的特性

我這里只是介紹目前可以使用的新特性,我這里試出來的貌似可以補充的就這么多了。其它還有一些尚未推出的特性等下次有了更新的版本再做介紹。感興趣的朋友可以看看官方的特性實現狀態文檔:http://roslyn.codeplex.com/wikipage?title=Language%20Feature%20Status&referringTitle=Home。目前比較期待的新特性是String interpolation模式匹配,尤其是模式匹配,希望能早日體驗一下。

另外,目前還沒有發現什么BCL方面的更新介紹,雖然BCL已經比較完善了,但感覺這次更新粒度蠻大的,估計至少會有一些基礎庫的補充的。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM