C# SWITCHの進化

# 概要
C#のバージョンアップでSwitchにいろいろな使い方が増えたから、メモとして使い方を纏めてみました。
文書で説明するのが大変だから、文書少なめでプログラムがメインに記述しました。

# 今までのSwitch
C# 6.0以前 switchのcaseラベルでは定数式のみ使用できます
``` C#:従来の使い方
int i = 0;
switch(i){
 case 10:
   Console.WriteLine("10");
   break;
 case 20:
   Console.WriteLine("20");
   break;
 case 30:
   Console.WriteLine("30");
   break;
 case 40:
   Console.WriteLine("40");
   break;
 default:
   Console.WriteLine("other");
   break;
}
//こんな感じでcaseラベルでは定数式のみ使用できます、
//そしてcaseラベルの定数式のの型は「char,string,bool,int,double,enum」等の組込み型だけ使用できます。
```

# バージョンアップ
だが以下のバージョンアップによって、今のswitchはいろんな使い方が増えました。
* C# 7.0　パターンマッチング機能の追加
* C# 8.0　switch式の導入
* C# 9.0　パターンマッチング機能の増強

# 新しいSwitchの使い方纏め
```C#:Switchステートメント
object objSwitch= 1l;
switch (objSwitch)
{
    //定数パターン
    case 10:
        Console.WriteLine("is 10");
        break;
    //定数と論理(or)パターン
    case 30 or 40 or 50:
        Console.WriteLine("is 30 or 40 or 50");
        break;
    //リレーションと論理(and)パターン
    case > 10 and < 20:
        Console.WriteLine("is > 10 and < 20");
        break;
    //型と論理(or)パターン
    case int or long:
        Console.WriteLine("is int or long");
        break;
    //型パターン
    case double:
        Console.WriteLine("is double");
        break;
    //型パターン
    case string:
        Console.WriteLine("is string");
        break;
    //「10」がintになる、case intで処理されるからここに記述するとエラーになる
    //case 10:
    //    Console.WriteLine("is 10");
    //    break;
    //破棄パターン
    // 「var _」が「default」似ている、
    // だが「var _」と「default」の前後順と関係なく「var _」が優先されるから、「default」が処理されなくなる
    case var _:
        Console.WriteLine("is other");
        break;
    // 但しswitchステートメントでは「default」を利用する方がより安全
    //default:
    //    Console.WriteLine("is other");
    //    break;
}

```
C# 8.0からswitch式が追加されたので、上記のswitchステートメントをswitch式に書き換えると
```C#:Switch式
//メソッドの戻り値が必須、switch式では何なかの値を帰す必要があります
public static string SwitchTest(object objSwitch) => objSwitch switch
{
    10 => "is 10",
    30 or 40 or 50 => "is 30 or 40 or 50",
    > 10 and < 20 => "is > 10 and < 20",
    int or long => "is int or long",
    double => "is double",
    string => "is string",
    _ => "is other"
};
```

SwitchプロパティパターンではSwitchのCaseの判断式に直接パラメータのプロパティやフィールドを利用できるようになりました。
```C#:Switchプロパティパターン
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
    public string Gender { get; set; }
    public string Tel { get; set; }
    public DateTime Birthday { get; set; }
}

//Switch式
public static string SwitchPeopleBlock(People people) => people switch
{
    { City:"東京",Age:30} => "A-1 block",
    { City: "東京", Age: 25 } => "A-2 block",
    { City: "東京", Age: >30 and < 40 } => "A-3 block",
    { City: "大阪", Age: 30 } => "B-1 block",
    { City: "大阪", Age: 25 } => "B-2 block",
    { City: "大阪", Age: > 30 and < 40 } => "B-3 block",
    { City: "東京", Age: 55 } or { City: "大阪", Age: 55 } => "C-1 block",
    _ => "NO block",
};


static void Main(string[] args)
{
	var p = new People { City = "東京", Age = 55 };
	Console.WriteLine(SwitchPeopleBlock(p));

    //Switchステートメント
	switch (p)
	{
	    case { City: "東京", Age: 30 }:
	        Console.WriteLine("A-1 block");
	        break;
	    case { City: "東京", Age: 25 }:
	        Console.WriteLine("A-2 block");
	        break;
	    case { City: "東京", Age: > 30 and < 40 }:
	        Console.WriteLine("A-3 block");
	        break;
	    case { City: "大阪", Age: 30 }:
	        Console.WriteLine("B-1 block");
	        break;
	    case { City: "大阪", Age: 25 }:
	        Console.WriteLine("B-2 block");
	        break;
	    case { City: "大阪", Age: > 30 and < 40 }:
	        Console.WriteLine("B-3 block");
	        break;
	    case { City: "東京", Age: 55 } or { City: "大阪", Age: 55 }:
	        Console.WriteLine("C-1 block");
	        break;
	    case var _:
	        Console.WriteLine("NO block");
	        break;
	}
}

```

Switchでタプル型の式も簡単処理できます
```C#:Switch位置指定パターン（タプル型）
public class People
{
    public string Name { get; set; }
    public int Age { get; set; }
    public string City { get; set; }
    public string Gender { get; set; }
    public string Tel { get; set; }
    public DateTime Birthday { get; set; }
}

//Switch式
public static string SwitchPeopleBlock(string City, int Age) => (City, Age) switch
{
    ("東京", 30 ) => "A-1 block",
    ("東京", 25 ) => "A-2 block",
    ("東京", > 30 and < 40 ) => "A-3 block",
    ("大阪", 30 ) => "B-1 block",
    ("大阪", 25 ) => "B-2 block",
    ("大阪", > 30 and < 40 ) => "B-3 block",
    ("東京", 55 ) or ( "大阪", 55 ) => "C-1 block",
    var (x, y) when y > 70 => "D-1 block",// varで使ってパラメータを一旦変数に保存してから計算することも可能
    //var (_, y) when y > 70 => "D-1 block",// 「_」で利用しない変数の不必要な代入を省ける
    _ => "NO block",
};


static void Main(string[] args)
{
	Console.WriteLine(SwitchPeopleBlock("東京", 30));
    Console.WriteLine(SwitchPeopleBlock("東京", 80));

    //Switchステートメント
    switch ("東京", 30)
	{
	    case ("東京", 30):
	        Console.WriteLine("A-1 block");
	        break;
	    case ("東京", 25):
	        Console.WriteLine("A-2 block");
	        break;
	    case ("東京", > 30 and < 40):
	        Console.WriteLine("A-3 block");
	        break;
	    case ("大阪", 30):
	        Console.WriteLine("B-1 block");
	        break;
	    case ("大阪", 25):
	        Console.WriteLine("B-2 block");
	        break;
	    case ("大阪", > 30 and < 40):
	        Console.WriteLine("B-3 block");
	        break;
	    case ("東京", 55) or ("大阪", 55):
	        Console.WriteLine("C-1 block");
	        break;
        // varで使ってパラメータを一旦変数に保存してから計算することも可能
        case var (x, y) when y > 70:
        //case var (_, y) when y > 70: 「_」で利用しない変数の不必要な代入を省ける
            Console.WriteLine("D-1 block");
            break;
	    case var _:
	        Console.WriteLine("NO block");
	        break;
	}
}

```