C#の条件分岐について学んだことをアウトプットします。
確認は .NET9 で行っています。
if文
if文に関してはC系統の言語によくある書き方です。
if
~if else
、else
の書き方ができます。
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
がないとビルドエラーになります。
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;
}
}
// 紫咲シオン
// 紫咲シオン
// 宝鐘マリン
// 宝鐘マリン
// 雪花ラミィ
// 雪花ラミィ
条件をつけて比較することも可能です。
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は冬です。
// 存在しない月です。
タプルでの比較
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;
}
}
// 塩っ子
// 宝鐘の一味
// 雪民
タプル型でも条件を付けた比較を行えます。
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
をつけることで更に詳細な条件を指定できます。
これをケースガードというようです。
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で評価した値を変数に直接代入することが可能です。
以下のように記述します。
var {変数名} = {比較元} switch
{
{比較先} => {結果},
{比較先} => {結果},
:
:
_ => {不一致結果},
}
case
は使用せずに、比較値 => 結果
という形式になります。
いずれにも一致しなかった場合のdefalut
はアンダースコア(_)を使用します。
var names4 = new[] { "塩っ子", "宝鐘の一味", "雪民", "ミオファ" };
foreach (var name in names4)
{
var value = name switch
{
"塩っ子" => "紫咲シオン",
"宝鐘の一味" => "宝鐘マリン",
"雪民" => "雪花ラミィ",
_ => "対応する名前が見つかりません。",
};
Console.WriteLine($"名前:{value}");
}
// 名前:紫咲シオン
// 名前:宝鐘マリン
// 名前:雪花ラミィ
// 名前:対応する名前が見つかりません。
パターンマッチング
is式、switch文、switch式を使用して特定のパターンに一致するか検証できます。
宣言パターン
指定された型と一致した場合に、後続で指定した変数に代入されます。
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です。
型パターン
変数を使用しない宣言パターンを型パターンというらしいです。
var data2 = new List<object> { 1208, "紫咲シオン", 'S' };
data2.ForEach(item =>
{
var message = item switch
{
string _ => $"塩っ子",
int _ => "12月8日",
char _ => "N",
_ => "想定外の方が指定されました。"
};
Console.WriteLine(message);
});
// 12月8日
// 塩っ子
// N
定数パターン
今まで記述していたif、switchのような書き方を定数パターンというようです。
var names = new[] { "紫咲シオン", "宝鐘マリン", "雪花ラミィ" };
foreach (var name in names)
{
switch (name)
{
case "紫咲シオン":
Console.WriteLine("塩っ子");
break;
case "宝鐘マリン":
Console.WriteLine("宝鐘の一味");
break;
case "雪花ラミィ":
Console.WriteLine("雪民");
break;
}
}
// 塩っ子
// 宝鐘の一味
// 雪民
リレーショナルパターン
caseに条件を加えたパターンをリレーショナルパターンというようです。
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
で条件を繋げるパターンのことです。
var items = new[] { -30, -20, -10, 0, 10, 20, 30 };
foreach (var item in items)
{
var result = item switch
{
<= 30 and > 0 => $"{item}は0以上30以下です。",
<= -20 or >= 20 => $"{item}はー20以下または20以上です。",
not -30 and not -10 and not 10 and not 30 => $"{item}はー30、ー10、10、30以外です。",
_ => $"{item}はいずれの条件にも一致しませんでした。",
};
Console.WriteLine(result);
}
// -30はー20以下または20以上です。
// -20はー20以下または20以上です。
// -10はいずれの条件にも一致しませんでした。
// 0はー30、ー10、10、30以外です。
// 10は0以上30以下です。
// 20は0以上30以下です。
// 30は0以上30以下です。
プロパティーパターン
一致した型のプロパティー値を比較することをいうようです。
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は雪花ラミィです。
入れ子になっているプロパティもアクセス可能です。
型 プロパティ: {プロパティ: 比較値}
というアクセス方法と型 { プロパティ.プロパティ: 比較値}
というアクセス方法があります。
後者を拡張プロパティパターンと呼ぶようです。
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);
}
// 塩っ子は紫咲シオンが好きです。
// 宝鐘の一味は宝鐘マリンが好きです。
// 雪民は雪花ラミィが好きです。
位置指定パターン
タプル型で使用したようなパターンのことのようです。
ただ、これだけではないようで、まだその部分に関しては勉強中です。
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パターン
使い方のイメージがいまいち沸かず、勉強中です。
リストパターン
リストの内容が一致するかを検証するパターンのようです。
[値, 値, 値, ...]
のような形式で指定します。
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
条件を先頭や末尾などの一部だけに指定したい場合、検証しない部分を..
で指定できます。
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