switch
一、switch 比對運算式的語法
switch 比對運算式提供與 case 標籤中的模式進行比對的值。 它的語法為:
switch (比對運算式)
{
}
如下範例
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int caseSwitch = 1;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
Console.WriteLine("Case 2");
break;
default:
Console.WriteLine("Default case");
break;
}
Console.ReadKey();
}
}
}
說明:
1、如果比對運算式不符合任何其他 case 標籤,則會跳到 default case (黃色框框)。
如果 default case 不存在,而且比對運算式不符合任何其他 case 標籤,則程式流程會離開 switch 陳述式。
2、default case 可以依任何順序出現在 switch 陳述式中。
不論它在原始程式碼中的順序為何,一律都會在評估過所有 case 標籤之後最後才進行評估。
3、在 C# 6 中,比對運算式必須是傳回下列類型之值的運算式︰char、string、bool、整數值、enum 值
4、從 C# 7 開始,比對運算式可以是任何非 Null 運算式。
二、參數區段
一個參數區段可以使用 break、return、goto case 或 throw 陳述式明確地指出來。
普遍地 switch 陳述式包含一個或多個參數區段,每一個參數區段都會由關鍵字「break」結尾。
如果某一參數區段沒有以關鍵字「break」結尾,而且底下也沒有陳述式時,
則該參數區段的處理方式會跟下一個參數區段合併。如下 case 2 到 case 3
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int caseSwitch = 2;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
case 3:
Console.WriteLine($"Case {caseSwitch}");
break;
default:
Console.WriteLine($"An unexpected value ({caseSwitch})");
break;
}
Console.ReadKey();
}
}
}
如果某一參數區段沒有以關鍵字「break」結尾,
而且底下還加上陳述式時,則會出錯,如下範例。
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int caseSwitch = 2;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
Console.WriteLine("Case 2");
//break;
case 3:
Console.WriteLine("Case 3");
break;
default:
Console.WriteLine($"An unexpected value ({caseSwitch})");
break;
}
Console.ReadKey();
}
}
}
另外,也不可以有兩個 case 標籤包含相同的運算式,如下範例是錯誤的。
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int caseSwitch = 2;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1");
break;
case 2:
case 2:
Console.WriteLine($"Case {caseSwitch}");
break;
default:
Console.WriteLine($"An unexpected value ({caseSwitch})");
break;
}
Console.ReadKey();
}
}
}
一個例外狀況也是有效的,因為它可確保程式控制權無法切換到 default 參數區段,如下範例。
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int caseSwitch = 2;
switch (caseSwitch)
{
case 1:
Console.WriteLine("Case 1...");
break;
case 2:
case 3:
Console.WriteLine("... and/or Case 2");
break;
case 4:
while (true)
Console.WriteLine("Endless looping. . . .");
default:
Console.WriteLine("Default value...");
break;
}
Console.ReadKey();
}
}
}
三、C# 7 case 標籤
從 C#1 到 C# 6 只支援常數模式,且不允許重複常數值,
所以 case 標籤定義互斥值,而且只有一個模式可以符合比對運算式。
因此,case 陳述式的出現順序並不重要。不過,在 C# 7 中,因為支援 pattern matching,
所以 case 標籤不需要定義互斥值,而且可以有多個模式符合比對運算式。
因為在 switch 判斷式中,只要一遇到符合條件的 case 就可跳離判斷式,
所以 case 陳述式的出現順序現在十分重要。
如果 C# 偵測到一或多個 case 陳述式等於或為先前陳述式子集的參數區段,
則會產生編譯器錯誤 CS8120:「The switch case has already been handled by a previous case.」,如下範例
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int switch_on = 2;
switch (switch_on)
{
case int a:
Console.WriteLine($"case int {a}");
break;
case 1:
Console.WriteLine("case 1");
break;
}
Console.ReadKey();
}
}
}
由於程式是依序比對,而「case int a」條件早已包含「case 1 」,
所以編譯器將會很聰明地發現錯誤CS8120:「The switch case has already been handled by a previous case.」
這時調整 case 的順序可以解決錯誤,或是使用關鍵字「when」來排除特例,如下範例
using System;
namespace ConsoleApp1
{
class Program
{
static void Main(string[] args)
{
int switch_on = 1;
switch (switch_on)
{
case int a when a != 1:
Console.WriteLine($"case int {a}");
break;
case 1:
Console.WriteLine("case 1");
break;
}
Console.ReadKey();
}
}
}
四、其他範例
public static int SumPositiveNumbers(IEnumerable<object> sequence)
{
int sum = 0;
foreach (var i in sequence)
{
switch (i)
{
case 0:
break;
case IEnumerable<int> childSequence:
{
foreach(var item in childSequence)
sum += (item > 0) ? item : 0;
break;
}
case int n when n > 0:
sum += n;
break;
case null:
throw new NullReferenceException("Null found in sequence");
default:
throw new InvalidOperationException("Unrecognized type");
}
}
return sum;
}
說明:
case 0: is the familiar constant pattern.
case IEnumerable<int> childSequence: is a type pattern.
case int n when n > 0: is a type pattern with an additional when condition.
case null: is the null pattern.
default: is the familiar default case.
參考資料: