C# 7新語法預覽

  • 12352
  • 0
  • 2016-06-10

Build 2016過後微軟投出了很多讓開發人員感到驚豔的震撼彈,像是Win10未來可以run原生的使用linux指令,Xamrian免費等等。趁著連假也惡補了幾段內容,其中「The Future of C#」談到了一些未來C# 7的新語法,讓人感到滿興奮的,因此在這邊做個簡單的紀錄。

有興趣的話可以看看The Future of C#的demo影片,非常精采!

※本篇所撰寫的C#7語法皆沒有實際貼到Visual Studio裡面編譯過,只是提出用法說明而已。

Binary literals

C# 7可以使用2進位的方式來表示數值內容,如同使用0xXX來表示16進位,現在也可以使用0bXX的方式來表示2進位數字。

例如過去我們宣告int number = 8;現在則可以改成int number = 0b1000;的方式來表達。

int num1 = 8;
int num2 = 0b1000;
Console.WriteLine($"Num1 = {num1}");
Console.WriteLine($"num2 = {num2}");
// 結果為
// Num1 = 8
// Num2 = 8

Digit separators

當宣告一個很多位數的數字時,我們可以使用底線(_)分隔數字來增加一定程度的可讀性,應用上則可以把它當作千分號來看待,如同比起閱讀1000000000,加上千份號的1,000,000,000比較容好讀。在宣告時可以變成宣告int num = 1_000_000_000;;這樣多少可以增加一點可讀性。

當然這個數字分隔符號不一定要當作千分號使用,你可以用任意的方式分隔數字,也不限制分隔符號只能使用一次,因此以下宣告結果都是一樣的:

// 傳統宣告方式
int num1 = 1000000;
// 當千份號使用
int num2 = 1_000_000;
// 隨便使用
int num3 = 1_00_00_00;
int num4 = 1__000___000;

當然啦如果隨意使用的話,可能反而會大幅降低可讀性就是了XD

Tuples

過去如果一個function想要有多個回傳值的話,有兩種方法,一種是把要接受回傳的資料當作參數丟到function裡面,並加上out代表參數用來作為回傳值:

        void GetHeightAndWeight(out int height, out int weight)
        {
            height = 172;
            weight = 80;
        }

        void OutputBody()
        {
            int height, weight;
            getHeightAndWeight(out height, out weight);
            Console.WriteLine($"Height = {height}");
            Console.WriteLine($"Weight = {weight}");
            // Height = 172
            // Weight = 80
        }

另一種方法是使用Tuple類別

        Tuple<int, int> GetHeightAndWeight()
        {
            var returnVal = new Tuple<int, int>(172, 80);
            return returnVal;
        }

        void OutputBody()
        {
            var body = GetHeightAndWeight();
            Console.WriteLine($"Height = {body.Item1}");
            Console.WriteLine($"Weight = {body.Item2}");
            // Height = 172
            // Weight = 80
        }

而針對Tuple類別,C# 7又額外提供了更容易撰寫的語法糖來使用,可以寫成這樣:

// 用括弧的方式直接代表Tuples
(int, int) GetHeightAndWeight(){
    var returnVal = (172, 80)
    return returnVal;
}

void OutputBody(){
    var body = GetHeightAndWeight();
    WriteLine("Height = {body.Item1}");
    WriteLine("Weight = {body.Item2}");
    // Height = 172
    // Weight = 80
}

不過Tuple其實最大的問題是Item1, Item2這樣的內容可讀性很差,因此C# 7也可以在宣告Tuples時,自訂一個名稱變數,之後就可以直接取用這個自訂的變數名稱了!

void OutputBody(){
    // 用自訂名稱來取代Tuple的Item1, Item2
    var body = (Height: 172, Weight: 80);
    WriteLine("Height = {body.Height}");
    WriteLine("Weight = {body.Weight}");
    // Height = 172
    // Weight = 80
}

Patten matching

Pattern matching主要是用來減少型別檢查時所需撰寫的程式碼,例如我們有一個object陣列,想要加總陣列裡面的整數部分時,過去我們程式碼會寫成這樣:

        static void Main(string[] args)
        {
            object[] numbers = { "a", 1, 2, "b", new object[] { 3, 4, 5 }};
            Console.WriteLine(sum(numbers));
        }

        static int sum(IEnumerable<object> list)
        {
            var result = 0;
            foreach(var val in list)
            {
                if (val is int)
                {
                    var num = (int)val;
                    result += num;
                }
            }
            return result;
        }

在sum函數裡的foreach迴圈中我們又要檢查型別又要進行轉型,其實是有點麻煩的,而在C# 7則可以用更簡易的寫法:

if (val is int num)
{
    result += num;
}

如此即可把型別檢查和轉型寫成一行,除此之外pattern matching也可以寫在switch裡面,另外在型別檢查時,還可以使用when限定條件:

        static int sum(IEnumerable<object> list)
        {
            var result = 0;
            foreach(var val in list)
            {
                switch(val)
                {
                    case int num:
                        result += num
                    break;
                    case IEnumerable<object> l when l.Any(): // 使用when做額外的條件限定
                        result += sum(l);
                    break;
                }
            }
            return result;
        }

Local functions

在C# 7裡面我們可在function裡面再包含一個local function,這個local function的可見範圍就只有目前function而已。

void func1()
{
    // local function
    int func2()
    {
        return 0;
    }
    var result = func2();
    Console.WriteLine($"Call func2() = {result}");
    // Call func2() = 0
}

void func3()
{
   var result = func2(); // 編譯錯誤
}

Ref returns and locals

過去我們可以把變數參考當作function的參數傳入,寫法如下:

void FuncRef(ref int data)
{
    // do something
}

在C# 7我們也可以直接把變數參考回傳回去了

        static void Main(string[] args)
        {
            int[] numbers = { 1, 2, 4 };
            // 回傳的是參考,不是值
            var firstRef = FirtRef(numbers);
        }

        static ref int FirstRef(ref int[] data)
        {
            // 回傳第一筆資料的參考
            return ref data[0];
        }

以上就是這次Build 2016所提到的C# 7的新語法,其中Tuples和Pattern matching個人感覺非常的實用,可以省下不少無謂的程式碼;其他語法可能是寫的code不夠多所以感覺不太出來應用方面XD。如果有時間建議直接看The Future of C#的影片,約一小時,demo的部分真的非常精彩,值得推薦啊!