条件分岐、switch文を理解しよう!

[C#] 条件分岐、switch文を理解しよう!

※ 当サイトは広告を含みます。

ここではC#のswitch文について理解しましょう。これはプログラムの基本構造で説明した選択にあたる処理です。
なお、プログラムの基本構造が分からない人は先に次の記事を読んでください。

switch statement (ステートメント)

if文と同じく条件分岐の処理になります。基本的にはif文と同じなのですが、switch文のほうが高度な記述ができます。

パターン1: switch 定数値

最もシンプルな記述はこれです。

パターン1: switch 定数値

評価値に記述できるのは数値や文字、文字列など、大抵の型は書けます。
また、caseは0個以上で好きなだけ記述できますが、defaultは0または1個だけです。

サンプルコードを用意してるので実行してみてください。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
          Console.WriteLine("1");
          break;

        case 2:
          Console.WriteLine("2");
          break;

        case 3:
          Console.WriteLine("3");
          break;

        default:
          Console.WriteLine("default");
          break;
      }
    }
  }
}
管理人
管理人

値に対して処理を分岐する場合はswitch文で記述したほうが美しいです。
また、caseの付近に書くのは:(コロン)なので注意してください。

パターン2: switch 条件式

なんと条件式も書けます。ちなみに定数値のcaseと併用も可能です。

パターン2: switch 条件式

namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 7;
      switch (n)
      {
        case > 10:
          Console.WriteLine("> 10");
          break;

        case > 5:
          Console.WriteLine("> 5");
          break;

        case > 3:
          Console.WriteLine("> 3");
          break;

        default:
          Console.WriteLine("default");
          break;
      }
    }
  }
}
管理人
管理人

if文と違い、満たせない条件を下に書くとエラーでビルドできません。
次のサンプルコードはエラーの例です。試しにビルドを試みてください。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 7;
      switch (n)
      {
        case > 1:
          Console.WriteLine("> 1");
          break;

        case > 10:
          Console.WriteLine("> 10");
          break;
      }
    }
  }
}
管理人
管理人

条件式はif文で書いたほうが分かりやすいので僕は使いません。

パターン3: switch 複数条件

複数の条件が1つのcaseを通るように記述できます。もちろん、defaultでも可能です。

パターン3: switch 複数条件

namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
        case 2:
        case 3:
          Console.WriteLine("1 or 2 or 3");
          break;

        default:
          Console.WriteLine("default");
          break;
      }
    }
  }
}
管理人
管理人

このパターンは便利なので覚えておいたほうがいいですよ。

パターン4: Case guards (ケースガード)

あまり使いませんが紹介だけしておきます。条件式を書く時に複雑な条件だとcase式で書けない場合があります。
これは例を見たほうが早いのでサンプルコードを用意しました。whenで記述してる部分がポイントです。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int x = 10;
      int y = 10;

      switch ((x, y))
      {
        case ( > 0, > 0) when x == y:
          Console.WriteLine("x == y");
          break;

        case ( > 0, > 0):
          Console.WriteLine("x > 0 & y > 0");
          break;

        default:
          Console.WriteLine("default");
          break;
      }
    }
  }
}
管理人
管理人

このようにwhenに追加の条件を記述することができます。ちなみに例のように複数の評価式を記述することも可能です。
ただし、このレベルになると理解しづらくなるので、無理にswitch文を使わずif文を使うほうが賢明でしょう。

スコープ

switch文の内部スコープは少し特殊です。
先に駄目な例を紹介するので、次のサンプルコードを確認してください。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
          int x = 1;
          break;

        case 2:
          int x = 1;
          break;
      }
    }
  }
}

どうですか? ビルドが通りませんよね。
これは複数のcase配下とdefault配下は同スコープで扱われるために、同名変数の定義エラーとなります。

では、どうするか。

最も簡単なのは上位で変数を宣言して使い回すことですが、スコープ範囲が増えるので良い記述ではありません。
これを解決する最も良い方法はcaseまたはdefaultの内部を{}で囲みブロック化します。そうすることで内部に新しいスコープを作ります。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
        {
          int x = 1;
          break;
        }

        case 2:
        {
          int x = 1;
          break;
        }
      }
    }
  }
}
管理人
管理人

同名の変数を作りたいことが多すぎて僕は常に{}で囲みます。と言うか仕様として元からスコープ分けてくれ。

fall through (フォールスルー)

C#では禁止されてますが内容は理解しておいてください。実はC言語など一部の言語には、フォールスルーと呼ばれる危険な仕様が存在します。
これはcaseの下にbreakを書かない記述法となり、何と次のcaseに処理が流れます。はっきり言ってバグの元でしかなく、禁止されるのも当然です。

仮にC#で書いた場合のサンプルコードです。case 1 を処理したら case 2 を処理、次に case 3 を処理って感じで全部通ります。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
          Console.WriteLine("1");

        case 2:
          Console.WriteLine("2");

        case 3:
          Console.WriteLine("3");
          break;
      }
    }
  }
}
管理人
管理人

ちなみに複数個のcaseを並べるパターンがフォールスルーっぽく見えますが、あれは違います。
フォールスルーとは、case配下を実行して、さらに次のcase配下を実行する処理です。

りさ
りさ

相変わらずC言語やばい。

goto併用

先程のフォールスルーが禁止されてる理由は、breakの記述を忘れて意図しない動作になるからです。
つまりは自分の意志で明確に記述した場合、フォールスルーと同等の動きでも問題ないと言えます。

そんな願いを叶えてくれるのがgoto文です。次のように記述すると別のcaseまたはdefaultにジャンプできます。


namespace Sample
{
  internal class Program
  {
    static void Main(string[] args)
    {
      int n = 1;
      switch (n)
      {
        case 1:
          Console.WriteLine("1");
          goto case 2;

        case 2:
          Console.WriteLine("2");
          goto case 3;

        case 3:
          Console.WriteLine("3");
          goto default;

        default:
          Console.WriteLine("default");
          break;
      }
    }
  }
}
管理人
管理人

goto文は賛否両論な構文です。本来はswitch文に縛られず使う構文なので、これは別の機会で説明します。

あとがき

昔はパターン1くらいしかなかったんだけど、気がついたら色々パターン増えてた。

◆ C#に関する学習コンテンツ

この記事は参考になりましたか?

関連記事

コメント

この記事へのコメントはありません。