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 索引子
參考資料: