C#の条件分岐についてのアウトプット

:::note info
C#の条件分岐について学んだことをアウトプットします。
:::
:::note info
確認は .NET9 で行っています。
:::

## if文
if文に関してはC系統の言語によくある書き方です。
`if`～`if else`、`else`の書き方ができます。

```cs:C#
var names = new[] { "紫咲シオン", "宝鐘マリン", "雪花ラミィ" };

foreach(var name in names)
{
    if (name == "紫咲シオン")
    {
        Console.WriteLine("塩っ子");
    }
    else if (name == "宝鐘マリン")
    {
        Console.WriteLine("宝鐘の一味");
    }
    else
    {
        Console.WriteLine("雪民");
    }
}

// 塩っ子
// 宝鐘の一味
// 雪民
```

## switch文
こちらも基本の書き方はC系統に似た書き方です。

条件には数値、文字、文字列、列挙型、タプルが指定できます。

C#のswitch文は文の末尾、または`default`までに`break`が必ず必要です。
また`defalut`にも`break`がないとビルドエラーになります。
```cs:C#
var names2 = new[] 
{ 
    "Shion", "塩っ子", 
    "Marine", "宝鐘の一味", 
    "Lamy", "雪民" 
};

foreach (var name in names2)
{
    switch (name)
    {
        case "Shion": case "塩っ子":
            Console.WriteLine("紫咲シオン");
            break;
        case "Marine": case "宝鐘の一味":
            Console.WriteLine("宝鐘マリン");
            break;
        default:
            Console.WriteLine("雪花ラミィ");
            break;
    }
}

// 紫咲シオン
// 紫咲シオン
// 宝鐘マリン
// 宝鐘マリン
// 雪花ラミィ
// 雪花ラミィ
```

条件をつけて比較することも可能です。
```cs:C#
var month = new[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 };

foreach (var m in month)
{
    switch(m)
    {
        case >= 3 and < 6:
            Console.WriteLine($"{m}は春です。");
            break;
        case >= 6 and < 9:
            Console.WriteLine($"{m}は夏です。");
            break;
        case >= 9 and < 12:
            Console.WriteLine($"{m}は秋です。");
            break;
        case 12 or (>= 1 and < 3):
            Console.WriteLine($"{m}は冬です。");
            break;
        default:
            Console.WriteLine("存在しない月です。");
            break;
    }
}

// 1は冬です。
// 2は冬です。
// 3は春です。
// 4は春です。
// 5は春です。
// 6は夏です。
// 7は夏です。
// 8は夏です。
// 9は秋です。
// 10は秋です。
// 11は秋です。
// 12は冬です。
// 存在しない月です。
```

タプルでの比較
```cs:C#
var names3 = new[]
{
    ("Shion", "紫咲シオン"),
    ("Marine", "宝鐘マリン"),
    ("Lamy", "雪花ラミィ"),
};

foreach (var name in names3)
{
    switch(name)
    {
        case ("Shion", "紫咲シオン"):
            Console.WriteLine("塩っ子");
            break;
        case ("Marine", "宝鐘マリン"):
            Console.WriteLine("宝鐘の一味");
            break;
        case ("Lamy", "雪花ラミィ"):
            Console.WriteLine("雪民");
            break;
    }
}

// 塩っ子
// 宝鐘の一味
// 雪民
```

タプル型でも条件を付けた比較を行えます。
```cs:C#
var points2 = new[] { (10, 20), (20, 20), (20, 10), (10, 0) };

foreach (var point in points2)
{
    switch (point)
    {
        case (>= 10, >= 10):
            Console.WriteLine($"条件に一致したポイントは{point}です。");
            break;
        case (<= 10, <= 10):
            Console.WriteLine($"条件に一致したポイントは{point}です。");
            break;
        default:
            Console.WriteLine($"条件に一致したポイントはありませんでした。");
            break;
    }
}

// 条件に一致したポイントは(10, 20)です。
// 条件に一致したポイントは(20, 20)です。
// 条件に一致したポイントは(20, 10)です。
// 条件に一致したポイントは(10, 0)です。
```

`when`をつけることで更に詳細な条件を指定できます。
これを**ケースガード**というようです。
```cs:C#
var points2 = new[] { (10, 20), (20, 20), (20, 10), (10, 10) };

foreach(var point in points2)
{
    switch (point)
    {
        case ( <= 20, <= 20) when point.Item1 == point.Item2:
            Console.WriteLine($"条件に一致したポイントは{point}です。");
            break;
        default:
            Console.WriteLine($"{point}は条件に一致しませんでした。");
            break;
    }
}

// (10, 20)は条件に一致しませんでした。
// 条件に一致したポイントは(20, 20)です。
// (20, 10)は条件に一致しませんでした。
// 条件に一致したポイントは(10, 10)です。
```


### switch式
C#のswitch文は式として扱うことも可能です。
switchで評価した値を変数に直接代入することが可能です。

以下のように記述します。
```cs:C#
var {変数名} = {比較元} switch
{
    {比較先} => {結果},
    {比較先} => {結果},
    :
    :
    _ => {不一致結果},
}
```

`case`は使用せずに、`比較値 => 結果`という形式になります。
いずれにも一致しなかった場合の`defalut`はアンダースコア(_)を使用します。

```cs:C#
var names4 = new[] { "塩っ子", "宝鐘の一味", "雪民", "ミオファ" };

foreach (var name in names4)
{
    var value = name switch
    { 
        "塩っ子" => "紫咲シオン",
        "宝鐘の一味" => "宝鐘マリン",
        "雪民" => "雪花ラミィ",
        _ => "対応する名前が見つかりません。",
    };

    Console.WriteLine($"名前：{value}");
}

// 名前：紫咲シオン
// 名前：宝鐘マリン
// 名前：雪花ラミィ
// 名前：対応する名前が見つかりません。
```

## パターンマッチング
is式、switch文、switch式を使用して特定のパターンに一致するか検証できます。

### 宣言パターン
指定された型と一致した場合に、後続で指定した変数に代入されます。
```cs:C#
var data = new List<object> { 1208, "紫咲シオン", 'S' };

data.ForEach(item =>
{
    var message = item switch
    {
        string shion => $"{shion}のファンネームは塩っ子です。",
        int birthday => $"誕生日は{birthday}です。",
        char initial => $"イニシャルは{initial}です。",
        _ => "想定外の型が指定されました。",
    };

    Console.WriteLine(message);
});

// 誕生日は1208です。
// 紫咲シオンのファンネームは塩っ子です。
// イニシャルはSです。
```
### 型パターン
変数を使用しない宣言パターンを型パターンというらしいです。
```cs:C#
var data2 = new List<object> { 1208, "紫咲シオン", 'S' };

data2.ForEach(item =>
{
    var message = item switch
    {
        string _ => $"塩っ子",
        int _ => "１２月８日",
        char _ => "N",
        _ => "想定外の方が指定されました。"
    };

    Console.WriteLine(message);
});

// １２月８日
// 塩っ子
// N
```

### 定数パターン
今まで記述していたif、switchのような書き方を定数パターンというようです。
```cs:C#
var names = new[] { "紫咲シオン", "宝鐘マリン", "雪花ラミィ" };

foreach (var name in names)
{
    switch (name)
    {
        case "紫咲シオン":
            Console.WriteLine("塩っ子");
            break;
        case "宝鐘マリン":
            Console.WriteLine("宝鐘の一味");
            break;
        case "雪花ラミィ":
            Console.WriteLine("雪民");
            break;
    }
}

// 塩っ子
// 宝鐘の一味
// 雪民
```
### リレーショナルパターン
caseに条件を加えたパターンをリレーショナルパターンというようです。
```cs:C#
var points = new[] { 10, 20, 30, 40, 50, 60, 70, 80, 90, 100 };

foreach (var point in points)
{
    switch(point)
    {
        case >= 80:
            Console.WriteLine($"{point}点は優秀です。");
            break;
        case >= 60:
            Console.WriteLine($"{point}点はほどほどです。");
            break;
        case >= 40:
            Console.WriteLine($"{point}点はまずいです。");
            break;
        default:
            Console.WriteLine($"{point}点は絶望的です。");
            break;
    }
}

// 10点は絶望的です。
// 20点は絶望的です。
// 30点は絶望的です。
// 40点はまずいです。
// 50点はまずいです。
// 60点はほどほどです。
// 70点はほどほどです。
// 80点は優秀です。
// 90点は優秀です。
// 100点は優秀です。
```

### 論理パターン
`not`、`and`、`or`で条件を繋げるパターンのことです。
```cs:C#
var items = new[] { -30, -20, -10, 0, 10, 20, 30 };

foreach (var item in items)
{
    var result = item switch
    {
        <= 30 and > 0 => $"{item}は０以上３０以下です。",
        <= -20 or >= 20 => $"{item}はー２０以下または２０以上です。",
        not -30 and not -10 and not 10 and not 30 => $"{item}はー３０、ー１０、１０、３０以外です。",
        _ => $"{item}はいずれの条件にも一致しませんでした。",
    };

    Console.WriteLine(result);
}

// -30はー２０以下または２０以上です。
// -20はー２０以下または２０以上です。
// -10はいずれの条件にも一致しませんでした。
// 0はー３０、ー１０、１０、３０以外です。
// 10は０以上３０以下です。
// 20は０以上３０以下です。
// 30は０以上３０以下です。
```

### プロパティーパターン
一致した型のプロパティー値を比較することをいうようです。
```cs:C#
var names2 = new[] { "MURASAKI SHION", "OOKAMI MIO", "YUKIHANA LAMY" };

foreach (var name in names2)
{
    var message = name switch
    {
        string { Length: >= 14 } s => $"{s}は紫咲シオンです。",
        string { Length: >= 13 } s => $"{s}は雪花ラミィです。",
        string { Length: >= 10 } s => $"{s}は大神ミオです。",
        _ => "いずれにも該当しません"
    };

    Console.WriteLine(message);
}

// MURASAKI SHIONは紫咲シオンです。
// OOKAMI MIOは大神ミオです。
// YUKIHANA LAMYは雪花ラミィです。
```

入れ子になっているプロパティもアクセス可能です。
`型 プロパティ: {プロパティ: 比較値}`というアクセス方法と`型 { プロパティ.プロパティ: 比較値}`というアクセス方法があります。

後者を拡張プロパティパターンと呼ぶようです。
```cs:C#
namespace Program;

class Program()
{
    public static void Main()
    {
        var members = new[]
        { 
            new Member("塩っ子"), new Member("宝鐘の一味"), new Member("雪民") 
        };

        foreach (var member in members)
        {
            var name = member switch
            {
                Member { Fun.Name: "塩っ子" } => "紫咲シオン",
                Member { Fun.Name: "宝鐘の一味" } => "宝鐘マリン",
                Member { Fun: { Name: "雪民" } } => "雪花ラミィ",
                _ => "いずれにも該当しません。",
            };

            Console.WriteLine($"{member.Fun.Name}は{name}が好きです。");
        }
    }
}


class Fun(string name)
{
    public string Name { get; set; } = name;
}
class Member(string name)
{
    public Fun Fun { get; set; } = new Fun(name);
}

// 塩っ子は紫咲シオンが好きです。
// 宝鐘の一味は宝鐘マリンが好きです。
// 雪民は雪花ラミィが好きです。
```

## 位置指定パターン
タプル型で使用したようなパターンのことのようです。
ただ、これだけではないようで、**まだその部分に関しては勉強中**です。
```cs:C#
var points2 = new[] 
{ 
    (0, 0), (0, 1), (0, 2), 
    (1, 0), (1, 1), (1, 2),
    (2, 0), (2, 1), (2, 2),
};

foreach (var point in points2)
{
    var message = point switch
    {
        (0, 0) => $"{point}は左下です。",
        (1, 1) => $"{point}は中央です。",
        (2, 2) => $"{point}は右上です。",
        _ => $"{point}はどこかにあるでしょう。",
    };

    Console.WriteLine(message);
}

// (0, 0)は左下です。
// (0, 1)はどこかにあるでしょう。
// (0, 2)はどこかにあるでしょう。
// (1, 0)はどこかにあるでしょう。
// (1, 1)は中央です。
// (1, 2)はどこかにあるでしょう。
// (2, 0)はどこかにあるでしょう。
// (2, 1)はどこかにあるでしょう。
// (2, 2)は右上です。
```

## varパターン
使い方のイメージがいまいち沸かず、勉強中です。

## リストパターン
リストの内容が一致するかを検証するパターンのようです。
`[値, 値, 値, ...]`のような形式で指定します。
```cs:C#
var numbers = new List<int>() { 10, 20, 30 };
Console.WriteLine($"numbers is [> 5, 20, 3 or 30] = {numbers is [> 5, 20, 3 or 30]}");
Console.WriteLine($"numbers is [10, 50, 30] = {numbers is [10, 50, 30]}");
Console.WriteLine($"numbers is [10, 20, 30, 40] = {numbers is [10, 20, 30, 40]}");

// numbers is [> 5, 20, 3 or 30] = True
// numbers is [10, 50, 30] = False
// numbers is [10, 20, 30, 40] = False
```

条件を先頭や末尾などの一部だけに指定したい場合、検証しない部分を`..`で指定できます。
```cs:C#
var numbers2 = new List<int>() { 10, 20, 30, 40, 50 };
Console.WriteLine($"numbers2 is [10, .., 50] = {numbers2 is [10, .., 50]}");

// numbers2 is [10, .., 50] = True
```