C# 7.0

 

一、binary literals and Digit separators

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] a = { 0b111, 2_54, 254 };
            int b = 2_54;
            int c = 1_23_45___6;
            int d = 0x1f;

            for (int i = 0; i < a.Length; i++)
            {
                Console.WriteLine($"a[{i}] = {a[i]}");
            }
            Console.WriteLine("b = " + b);
            Console.WriteLine("c = " + c);
            Console.WriteLine("d = " + d);

            Console.ReadKey();
        }
    }
}

結果為

說明:

1、以前C#除了十進位表示之外,只有提供十六進位表示如「int d = 0x1f;」,

但現在還提供了二進位表示「int d = 0b111;」,真是太棒了。

2、數字分隔符號(底線),「int a = 254;」就等於「int a = 2_54;」也等於「int a = 2___5__4;」,

由範例可知,該數字分隔符號就像是注解一樣,幫助開發者增加一點可讀性。

 

二、ValueTuple (tuple types)

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Tuple<int, int> rr = new Tuple<int, int>(100, 200);
            Console.WriteLine($"rr.Item1 = {rr.Item1}, rr.Item2 = {rr.Item2}");

            ValueTuple<int, int> r = (100, 200);
            Console.WriteLine($"r.Item1 = {r.Item1}, r.Item2 = {r.Item2}");

            var r2 = (myItem: 111, 399);
            Console.WriteLine($"r2.myItem = {r2.myItem}, r2.Item2 = {r2.Item2}");

            var t = Tally();
            Console.WriteLine($"Sum: {t.sum}, count: {t.count}");

            var (sum1, count1) = Tally();
            Console.WriteLine($"Sum1: {sum1}, count1: {count1}");

            string name = "";
            int cash = 0;
            (name, cash) = ("tom", 100);
            Console.WriteLine($"name: {name}, cash: {cash}");

            Console.ReadKey();
        }

        static (int sum, int count) Tally()
        {
            var result = (s: 123, c: 456);
            return result;
        }
    }
}

結果為

說明:

1、使用ValueTuple時需注意要運行在.NET Framework 4.7以上版本。

2、看到Mads Torgersen在介紹C# 7.0的Tuples很精彩(New Features in C# 7.0),但是要注意,

此Tuples是指ValueTuple結構,而不是Tuple類別,兩者用法幾乎一模一樣。

3、兩個以上的值組就可以使用Tuple結構,如「var r = (100, 200);」。

4、tuple變數預設使用Item1、Item2…名稱就可以取值,也可以自行命名來取值,如

var r2 = (myItem: 111, 399);
Console.WriteLine($"r2.myItem = {r2.myItem}, r2.Item2 = {r2.Item2}");

5、function的回傳值也可以用Tuple結構回傳,function的回傳值也可自訂如:

static (int sum, int count) Tally(){}

6、function內將要回傳的Tuple值名稱不一定要跟function所宣告回傳名稱對得起來,

只要順序對就行了。

static (int sum, int count) Tally()
{
    var result = (s: 123, c: 456);
    return result;
}

另外一種使用tuple的方法就是Tuple的解構(deconstruct)寫法,

宣告的自訂名稱跟function回傳的自訂名稱不需一樣,只要順序對就行了。

var (sum1, count1) = Tally();
Console.WriteLine($"Sum1: {sum1}, count1: {count1}");

 

三、local function

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            string input = "100,200,300";
            Console.WriteLine($"Sum equal to {Sum(input)}");
            Console.ReadKey();
        }

        static int Sum(string a)
        {
            string[] b = a.Split(new char[] { ',' });
            return MyConvert(b);

            int MyConvert(string[] c)
            {
                int result = 0;
                foreach (string item in c)
                {
                    result += Convert.ToInt32(item); ;
                }
                return result;
            }
        }
    }
}

如上範例,一個function裡面再包含一個local function,

該local function故名思意只能在本地使用,外界根本看不到他。

 

四、pattern matching

pattern matching 可應用在 if 或 switch 判斷式,主要有四種 pattern matching 型式,

分別是 Constant pattern、Type pattern、var pattern、null pattern。

1、Constant pattern

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<int> dList = new List<int>();
            if (dList is null)
            {
                Console.WriteLine("variable dList is null");
            }
            else
            {
                Console.WriteLine("variable dList is not null");
            }

            string myString = "abc";
            if (myString is "aaa")
            {
                Console.WriteLine("variable myString is aaa");
            }
            else
            {
                Console.WriteLine("variable myString is not equal to aaa");
            }
            Console.ReadKey();
        }
    }
}

關鍵字「is」可以用來判斷是否等於Null、等於一個常數。

 

2、Type pattern

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            BMW BMW = new BMW();
            if (BMW is Car test)
            {
                Console.WriteLine($"BMW is Car test, test.weight = {test.weight}");
            }
            Car o = BMW as Car;
            if (o != null)
            {
                Console.WriteLine($"variable BMW is Car o, o.weight = {o.weight}");
            }

            ///////////////////////////////////////////////////////////////////////
            if (BMW is BMW test2)
            {
                Console.WriteLine($"BMW is BMW test2, test2.ABS = {test2.ABS}");
            }
            BMW o2 = BMW as BMW;
            if (o2 != null)
            {
                Console.WriteLine($"variable BMW is BMW o2, o2.ABS = {o2.ABS}");
            }

            ///////////////////////////////////////////////////////////////////////
            Car Car = new Car();
            if (Car is BMW test3)
            {
                Console.WriteLine($"Car is BMW test3, test3.ABS = {test3.ABS}");
            }
            BMW o3 = Car as BMW;
            if (o3 != null)
            {
                Console.WriteLine($"variable Car is BMW o3, o3.ABS = {o3.ABS}");
            }

            ///////////////////////////////////////////////////////////////////////
            if (Car is Car test4)
            {
                Console.WriteLine($"Car is Car test4, test4.weight = {test4.weight}");
            }
            Car o4 = Car as Car;
            if (o4 != null)
            {
                Console.WriteLine($"variable Car is Car o4, o4.weight = {o4.weight}");
            }

            Console.ReadKey();
        }
    }

    class Car
    {
        public int weight = 100;
    }

    class BMW : Car
    {
        public Boolean ABS = true;
        public BMW()
        {
            weight = 600;
        }
    }
}

結果為

搭配關鍵字「is」的表達式,如範例中的黃色框框「BMW is Car test」

可以用來判斷一變數是否為Null,

並且判斷一變數是否符合指定形態,如果符合的話,

則會將該變數轉型為指定形態以供開發者操作。

搭配關鍵字「is」的表達式,其處理方式

if (BMW is Car test)
{
    Console.WriteLine($"BMW is Car test, test.weight = {test.weight}");
}

相等於

Car o = BMW as Car;
if (o != null)
{
    Console.WriteLine($"variable BMW is Car o, o.weight = {o.weight}");
}

 

3、var pattern

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            BMW BMW = new BMW();
            if (BMW is var test)
            {
                Console.WriteLine($"test.ABS = {test.ABS}");
            }
            Console.WriteLine($"can be use on if expression outside, test.ABS = {test.ABS}");

            Car Car = null;
            if (Car is var test2)
            {
                if (test2 != null)
                {
                    Console.WriteLine($"test2.weight = {test2.weight}");
                }
            }

            Console.ReadKey();
        }
    }

    class Car
    {
        public int weight = 100;
    }

    class BMW : Car
    {
        public Boolean ABS = true;
        public BMW()
        {
            weight = 600;
        }
    }
}

結果為

使用var pattern方式則其表達式永遠都會成立,如上例黃色框框「BMW is var test」,

很奇怪的是,就算變數是null也可以過的了使用var pattern的 if判斷式,

所以注意要在 if判斷式 裡加以判斷是否為null,才不會出錯。

另外要注意的一點就是被assign的「test」、「test2」變數,都是靜態變數。

 

在 C# 7.0 之前,關鍵字「is」只能用來比較一變數是否符合某一形態,

而比較一變數是否為 Null 則只能使用「==」運算子(operator),

但現在於 C# 7.0,關鍵字「is」也可以用來比較 Null 了。

using System;
using System.Collections.Generic;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Car myCar = new Car();
            if (myCar is BMW)
            {
                Console.WriteLine("variable " + "myCar" + " is the type of " + typeof(BMW));
            }
            else
            {
                Console.WriteLine("variable " + "myCar" + " is not the type of " + typeof(BMW));
            }

            List<int> cNull = null;
            if (cNull == null)
            {
                Console.WriteLine("variable cNull is null");
            }
            else
            {
                Console.WriteLine("variable cNull is not null");
            }
            Console.ReadKey();
        }
    }

    class Car { }

    class BMW : Car { }
}

 

五、out

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            Call();
            /*below the commented code,can not to be executed*/
            //Console.WriteLine($"({x}, {y})");
            Console.ReadKey();
        }

        static void Call()
        {
            GetCoordinates(out int x, out int y);
            Console.WriteLine($"({x}, {y})");
        }

        static void GetCoordinates(out int a, out int b)
        {
            a = 100;
            b = 200;
        }
    }
}

說明:

1、現在參數修飾詞「out」也可以在傳遞時再宣告,這可以減少程式碼的行數,增加可讀性。

2、這個變數在包含它本身的 { } 封閉區塊範圍內,所以接續宣告後面的程式碼可以直接使用這些變數。

3、如果你不在意某個 out 參數的傳回結果,可以使用 _ 代表忽略它:

static void Call()
{
    GetCoordinates(out int x, out _);
    Console.WriteLine($"({x})");
}

 

六、Ref returns and locals

using System;

namespace ConsoleApp1
{
    class Program
    {
        static void Main(string[] args)
        {
            int[] array = { 1, 15, -39, 0, 7, 14, -12 };

            foreach (var item in array)
            {
                Console.Write(item + ", ");
            }

            ref int place = ref Find(7, array);
            place = 9;
            Console.WriteLine();

            foreach (var item in array)
            {
                Console.Write(item + ", ");
            }

            Console.ReadKey();
        }

        public static ref int Find(int number, int[] numbers)
        {
            for (int i = 0; i < numbers.Length; i++)
            {
                if (numbers[i] == number)
                {
                    return ref numbers[i]; // return the storage location, not the value
                }
            }
            throw new IndexOutOfRangeException($"{nameof(number)} not found");
        }
    }
}

畫面為

以前使用過修飾詞「ref」的方式傳遞參數,

你現在也可以用同樣的方式將區域變數的數值用參考的方式傳回。

 

七、Indexer

請參考 Indexers 索引子

 

參考資料:

Pattern Matching

ValueTuple Struct

如何:使用 as 和 is 運算子進行安全轉型 (C# 程式設計手冊)

is (C# Reference)

The future of C# (youtube)

C# tuple types