C#のswitch文で複数のcase条件を使いこなす方法

C#のswitch文は、条件分岐を簡潔に記述できる強力な機能です。特に、複数のcase条件を使用することで、コードの可読性と保守性を大幅に向上させることができます。
この記事では、C#のswitch文における複数のcase条件の使用方法や、関連する高度なテクニックについて詳しく解説します。

記事のポイント

  • C#のswitch文の基本的な使い方と複数のcase条件の活用方法
  • whenキーワードを使用した条件付きのcase文の実装
  • パターンマッチングを活用した柔軟なswitch文の記述
  • 比較演算子を用いたswitch文の拡張
  • ネストされたswitch文の適切な使用方法
  • switch文の代替手法と使用時の注意点
目次

C#のswitch文で複数のcase条件を効果的に使用する方法

switch文は、単一の変数や式の値に基づいて複数の実行パスを選択するためのプログラミング構造です。
C#では、switch文を使用することで、if-elseの連鎖よりも読みやすく、効率的なコードを書くことができます。
ここでは、複数のcase条件を使用する際の基本的な構文と、その応用について説明します。

基本的なswitch文の構造

まず、C#におけるswitch文の基本的な構造を確認しましょう。

switch (expression)
{
    case constant1:
        // constant1に一致した場合の処理
        break;
    case constant2:
        // constant2に一致した場合の処理
        break;
    // ... 他のcase文 ...
    default:
        // どのcaseにも一致しなかった場合の処理
        break;
}

この構造では、expressionの値が各caseのラベルと比較され、一致したcaseブロック内のコードが実行されます。

複数の条件を1つのcaseにまとめる

C# 7.0以降では、複数の条件を1つのcase文にまとめることができます。これにより、コードの重複を減らし、可読性を向上させることができます。

int dayNumber = 3;
string dayType;

switch (dayNumber)
{
    case 1:
    case 2:
    case 3:
    case 4:
    case 5:
        dayType = "平日";
        break;
    case 6:
    case 7:
        dayType = "週末";
        break;
    default:
        dayType = "無効な日";
        break;
}

Console.WriteLine($"日付タイプ: {dayType}");

この例では、複数のcaseラベルを連続して記述することで、同じ処理を共有しています。
これにより、コードの重複を避けつつ、複数の条件に対して同じ処理を適用することができます。

whenキーワードを使用した条件付きcase

C# 7.0で導入されたwhenキーワードを使用すると、より複雑な条件をcase文に追加することができます。
これにより、switch文の柔軟性が大幅に向上します。

int score = 85;
string grade;

switch (score)
{
    case int n when n >= 90:
        grade = "A";
        break;
    case int n when n >= 80:
        grade = "B";
        break;
    case int n when n >= 70:
        grade = "C";
        break;
    case int n when n >= 60:
        grade = "D";
        break;
    default:
        grade = "F";
        break;
}

Console.WriteLine($"成績: {grade}");

この例では、whenキーワードを使用して、各caseに追加の条件を設定しています。
これにより、数値範囲に基づいた条件分岐を簡潔に記述することができます。

パターンマッチングを活用したswitch文

C# 7.0以降では、switch文でパターンマッチングを使用することができます。
これにより、型チェックと値の抽出を同時に行うことが可能になり、より表現力豊かなコードを書くことができます。

object obj = "Hello, World!";
string result;

switch (obj)
{
    case int i:
        result = $"整数値: {i}";
        break;
    case string s when s.Length > 10:
        result = $"長い文字列: {s}";
        break;
    case string s:
        result = $"文字列: {s}";
        break;
    case null:
        result = "nullオブジェクト";
        break;
    default:
        result = "未知の型";
        break;
}

Console.WriteLine(result);

この例では、objの型に基づいて異なる処理を行っています。さらに、文字列の場合は長さによって条件を分けています。パターンマッチングを使用することで、型チェックと条件チェックを組み合わせた複雑な分岐を簡潔に記述できます。

C#のswitch文でwhenキーワードを活用する高度なテクニック

C# 7.0で導入されたwhenキーワードは、switch文の機能を大幅に拡張しました。このセクションでは、whenキーワードを使用したより高度なswitch文の活用方法について詳しく説明します。

複雑な条件を持つcase文の実装

whenキーワードを使用すると、単純な値の比較だけでなく、より複雑な条件をcase文に追加することができます。これにより、switch文の表現力が大幅に向上し、より柔軟な条件分岐が可能になります。

DateTime date = DateTime.Now;
string message;

switch (date.DayOfWeek)
{
    case DayOfWeek.Monday when date.Day <= 7:
        message = "今月の最初の月曜日です";
        break;
    case DayOfWeek.Friday when date.Day >= 25:
        message = "今月の最後の金曜日です";
        break;
    case DayOfWeek.Saturday:
    case DayOfWeek.Sunday:
        message = "週末です";
        break;
    default:
        message = "平日です";
        break;
}

Console.WriteLine(message);

この例では、whenキーワードを使用して、曜日だけでなく日付も考慮した条件分岐を実装しています。
これにより、より具体的で複雑な条件に基づいた処理を簡潔に記述することができます。

複数の変数を考慮したswitch文

whenキーワードを使用すると、switch文の式以外の変数も条件に含めることができます。これにより、複数の要因を考慮した複雑な分岐ロジックを実装することが可能になります。

int temperature = 25;
bool isRaining = true;

string weatherAdvice = (temperature, isRaining) switch
{
    ( >= 30, false) => "暑いです。日よけを使用してください。",
    ( >= 30, true ) => "蒸し暑いです。傘と水分補給を忘れずに。",
    ( >= 20 and < 30, false) => "過ごしやすい天気です。",
    ( >= 20 and < 30, true ) => "雨が降っています。傘を忘れずに。",
    ( < 20, false ) => "涼しいです。上着を着てください。",
    ( < 20, true  ) => "寒く雨が降っています。暖かい服装と傘を。"
};

Console.WriteLine(weatherAdvice);

この例では、気温と雨の有無という2つの要因を考慮して天気のアドバイスを生成しています。
C# 8.0以降で導入されたタプルパターンと組み合わせることで、複数の条件を簡潔に表現することができます。

メソッド呼び出しを含む条件

whenキーワードを使用すると、メソッド呼び出しを含む複雑な条件も指定できます。
これにより、より動的で柔軟な条件分岐が可能になります。

string GetDiscountType(Customer customer)
{
    return customer switch
    {
        { Purchases: var p }  when p.Count() > 100 => "プラチナ会員",
        { TotalSpent: var t } when t > 10000       => "ゴールド会員",
        { JoinDate: var d }   when (DateTime.Now - d).TotalDays > 365 => "シルバー会員",
        _ => "一般会員"
    };
}


class Customer
{
    public List<Purchase> Purchases { get; set; }
    public decimal TotalSpent { get; set; }
    public DateTime JoinDate { get; set; }
}

class Purchase
{
    public decimal Amount { get; set; }
    public DateTime Date { get; set; }
}

この例では、顧客オブジェクトの各プロパティに対して複雑な条件を適用し、適切な割引タイプを決定しています。メソッド呼び出しや計算を含む条件を使用することで、より高度で動的な分岐ロジックを実装することができます。

C#のswitch文でパターンマッチングを活用する高度な手法

C# 7.0以降で導入されたパターンマッチングは、switch文の機能を大幅に拡張し、より表現力豊かなコードを書くことを可能にしました。
このセクションでは、switch文でのパターンマッチングの高度な使用方法について詳しく説明します。

型パターンを使用した柔軟な分岐

型パターンを使用すると、オブジェクトの型に基づいて分岐処理を行うことができます。これにより、異なる型のオブジェクトに対して適切な処理を簡潔に記述することが可能になります。

object item = new Circle { Radius = 5 };
string result;

switch (item)
{
    case Circle c:
        result = $"円の面積: {Math.PI * c.Radius * c.Radius:F2}";
        break;
    case Rectangle r:
        result = $"長方形の面積: {r.Width * r.Height}";
        break;
    case Triangle t:
        double s = (t.SideA + t.SideB + t.SideC) / 2;
        double area = Math.Sqrt(s * (s - t.SideA) * (s - t.SideB) * (s - t.SideC));
        result = $"三角形の面積: {area:F2}";
        break;
    case null:
        result = "nullオブジェクト";
        break;
    default:
        result = "未知の図形";
        break;
}

Console.WriteLine(result);


class Circle { public double Radius { get; set; } }
class Rectangle { public double Width { get; set; } public double Height { get; set; } }
class Triangle { public double SideA { get; set; } public double SideB { get; set; } public double SideC { get; set; } }

この例では、異なる図形クラスのオブジェクトに対して、それぞれ適切な面積計算を行っています。
型パターンを使用することで、型チェックと変数宣言を同時に行い、コードをより簡潔にすることができます。

プロパティパターンを使用した詳細な条件分岐

C# 8.0で導入されたプロパティパターンを使用すると、オブジェクトのプロパティに基づいてより詳細な条件分岐を行うことができます。

var person = new Person { Name = "Alice", Age = 25 };
string description;

switch (person)
{
    case { Name: "Alice", Age: 25 }:
        description = "25歳のAliceです";
        break;
    case { Name: "Bob" } when person.Age >= 18:
        description = "成人したBobです";
        break;
    case { Age: var age } when age < 18:
        description = $"{age}歳の未成年者です";
        break;
    default:
        description = "その他の人物です";
        break;
}

Console.WriteLine(description);


class Person
{
    public string Name { get; set; }
    public int Age { get; set; }
}

この例では、Personオブジェクトのプロパティに基づいて詳細な条件分岐を行っています。プロパティパターンを使用することで、オブジェクトの内部状態に基づいた複雑な条件を簡潔に表現することができます。

タプルパターンを使用した複数の値の同時チェック

C# 8.0以降では、タプルパターンを使用して複数の値を同時にチェックすることができます。
これにより、複数の条件を組み合わせた複雑な分岐ロジックを簡潔に記述することが可能になります。

static string ClassifyPoint(int x, int y)
{
    return (x, y) switch
    {
        (0, 0) => "原点",
        (_, 0) => "X軸上",
        (0, _) => "Y軸上",
        _ when x > 0 && y > 0 => "第一象限",
        _ when x < 0 && y > 0 => "第二象限",
        _ when x < 0 && y < 0 => "第三象限",
        _ when x > 0 && y < 0 => "第四象限",
        _ => "予期しない座標"
    };
}

Console.WriteLine(ClassifyPoint(5, 3));   // 出力: 第一象限
Console.WriteLine(ClassifyPoint(-2, 4));  // 出力: 第二象限
Console.WriteLine(ClassifyPoint(0, -1));  // 出力: Y軸上

この例では、2次元平面上の点の位置を分類しています。タプルパターンを使用することで、x座標とy座標を同時にチェックし、適切な分類を行っています。
これにより、複数の値に基づいた複雑な条件分岐を非常に読みやすい形で表現することができます。

再帰的パターンを使用したネストされたオブジェクトの分析

C# 8.0以降では、再帰的パターンを使用して、ネストされたオブジェクトの構造を分析することができます。
これは、複雑なデータ構造を持つオブジェクトを扱う際に特に有用です。

static string DescribePerson(Person person)
{
    return person switch
    {
        { Name: "Alice" , Address: { City: "Tokyo" }  } => "東京在住のAlice",
        { Name: "Bob"   , Address: { City: var city } } => $"{city}在住のBob",
        { Name: var name, Address: null               } => $"{name}(住所不明)",
        { Name: var name, Address: { City: var city } } => $"{city}在住の{name}",
        null => "人物情報なし"
    };
}

var alice   = new Person { Name = "Alice"  , Address = new Address { City = "Tokyo" } };
var bob     = new Person { Name = "Bob"    , Address = new Address { City = "Osaka" } };
var charlie = new Person { Name = "Charlie", Address = null };

Console.WriteLine(DescribePerson(alice));    // 出力: 東京在住のAlice
Console.WriteLine(DescribePerson(bob));      // 出力: Osaka在住のBob
Console.WriteLine(DescribePerson(charlie));  // 出力: Charlie(住所不明)


class Address { public string City { get; set; } }
class Person { public string Name { get; set; } public Address Address { get; set; } }

この例では、PersonオブジェクトとそのネストされたAddressオブジェクトの構造を分析しています。再帰的パターンを使用することで、深くネストされたプロパティに対しても簡潔に条件を指定することができます。

パターンマッチングを活用した例外処理

パターンマッチングは例外処理にも適用することができ、より詳細で型安全な例外処理を実現することができます。

try
{
    // 何らかの処理
    throw new ArgumentException("無効な引数", "paramName");
}
catch (Exception ex)
{
    string errorMessage = ex switch
    {
        ArgumentException ae when ae.ParamName == "paramName"
            => $"パラメータエラー: {ae.Message}",
        ArgumentNullException ane
            => $"null参照エラー: {ane.ParamName}がnullです",
        InvalidOperationException ioe
            => $"不正な操作: {ioe.Message}",
        _ => $"予期しないエラー: {ex.Message}"
    };
    Console.WriteLine(errorMessage);
}

この例では、catch節で捕捉した例外オブジェクトに対してswitch式とパターンマッチングを適用しています。
これにより、例外の型や特定のプロパティの値に基づいて、より詳細なエラーメッセージを生成することができます。

C#のswitch文での比較演算子の活用

C# 7.0以降では、switch文内で比較演算子を使用することが可能になり、数値範囲や複雑な条件に基づいた分岐をより簡潔に記述できるようになりました。
このセクションでは、switch文での比較演算子の効果的な使用方法について説明します。

数値範囲に基づいた分岐

比較演算子を使用することで、連続した数値範囲に基づいた分岐を簡潔に記述することができます。

static string GradeStudent(int score)
{
    return score switch
    {
        < 60 => "不可",
        < 70 => "可",
        < 80 => "良",
        < 90 => "優",
        <= 100 => "秀",
        _ => "無効な点数"
    };
}

Console.WriteLine(GradeStudent(75));  // 出力: 良
Console.WriteLine(GradeStudent(95));  // 出力: 秀
Console.WriteLine(GradeStudent(50));  // 出力: 不可

この例では、学生の点数に基づいて成績を判定しています。比較演算子を使用することで、if-elseの連鎖よりも簡潔で読みやすいコードを記述することができます。

複合条件の使用

比較演算子と論理演算子を組み合わせることで、より複雑な条件に基づいた分岐を実装することができます。

static string ClassifyTemperature(double temperature, string scale)
{
    return (temperature, scale) switch
    {
        ( <= 0          , "C") or ( <= 32         , "F") => "氷点下",
        ( >  0  and < 20, "C") or ( >  32 and < 68, "F") => "寒い",
        ( >= 20 and < 30, "C") or ( >= 68 and < 86, "F") => "快適",
        ( >= 30         , "C") or ( >= 86         , "F") => "暑い",
        _ => "無効な入力"
    };
}

Console.WriteLine(ClassifyTemperature(15, "C"));   // 出力: 寒い
Console.WriteLine(ClassifyTemperature(75, "F"));   // 出力: 快適
Console.WriteLine(ClassifyTemperature(35, "C"));   // 出力: 暑い

この例では、温度と温度スケール(摂氏または華氏)に基づいて気温を分類しています。比較演算子と論理演算子を組み合わせることで、複雑な条件を簡潔に表現しています。

C# 9.0のrelationalパターンの活用

C# 9.0で導入されたrelationalパターンを使用すると、より柔軟な数値範囲の比較が可能になります。

static string ClassifyAge(int age)
{
    return age switch
    {
        <= 12           => "子供",
        >  12 and <= 19 => "ティーンエイジャー",
        >  19 and <= 59 => "大人",
        >= 60           => "シニア"
    };
}

Console.WriteLine(ClassifyAge(8));   // 出力: 子供
Console.WriteLine(ClassifyAge(16));  // 出力: ティーンエイジャー
Console.WriteLine(ClassifyAge(35));  // 出力: 大人
Console.WriteLine(ClassifyAge(70));  // 出力: シニア

この例では、年齢に基づいて人物を分類しています。relationalパターンを使用することで、連続した範囲や複雑な条件を簡潔に表現することができます。

C#のswitch文における複数の条件の組み合わせ方

最後に、これまで学んだテクニックを組み合わせて、より複雑な条件分岐を実装する方法を紹介します。以下の例では、商品の割引率を決定するロジックを実装しています。

var product1 = new Product { Category = "Electronics", Price = 1200 };
var product2 = new Product { Category = "Clothing", ListingDate = DateTime.Now.AddDays(-45) };
var product3 = new Product { Category = "Books", Price = 15 };

Console.WriteLine($"製品1の割引率: {CalculateDiscount(product1):P}");  // 出力: 製品1の割引率: 10.00%
Console.WriteLine($"製品2の割引率: {CalculateDiscount(product2):P}");  // 出力: 製品2の割引率: 20.00%
Console.WriteLine($"製品3の割引率: {CalculateDiscount(product3):P}");  // 出力: 製品3の割引率: 5.00%


class Product
{
    public string Category { get; set; }
    public decimal Price { get; set; }
    public DateTime ListingDate { get; set; }
}

static decimal CalculateDiscount(Product product)
{
    return product switch
    {
        { Category: "Electronics", Price: > 1000 } => 0.1m,
        { Category: "Clothing"   , ListingDate: var d } when (DateTime.Now - d).TotalDays > 30 => 0.2m,
        { Category: "Books"      , Price: < 20 }   => 0.05m,
        { Category: "Books"      , Price: >= 20 }  => 0.1m,
        { Price: > 100 }                           => 0.05m,
        _ => 0m
    };
}

この例では、商品のカテゴリー、価格、掲載日などの複数の要因を考慮して割引率を決定しています。
プロパティパターン、比較演算子、whenキーワードを組み合わせることで、複雑なビジネスロジックを簡潔かつ読みやすい形で表現しています。

C#のswitch文によるメインキーワードのまとめ

C#のswitch文、特に複数のcase条件を使用する手法はコードの可読性と保守性を大幅に向上させる強力なツールです。本記事で紹介したテクニックを適切に活用することで、複雑な条件分岐を含むプログラムをより効率的に実装することができます。
パターンマッチング、whenキーワード、比較演算子などの機能を組み合わせることで、C#のswitch文はより表現力豊かで柔軟なものとなります。
これらの機能を使いこなすことで、より簡潔で理解しやすいコードを書くことができ、結果としてバグの少ない、保守性の高いソフトウェアの開発につながります。

関連ページ

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!
目次