条件分岐編集

if文編集

if文(「イフぶん」と読む)は、条件式に基づいて分岐し分岐先の文を実行します。

C#のif文の記法や使い方は、標準C言語やC++とほぼ同じですが、条件式にbool型の式しか使えないところが違います。

if文の例
using System;

public class Hello {
  public static void Main(string[] args) {
    int a = 7;

    if (a > 5) {
      Console.WriteLine("5より大きい");
    }

    if (a <= 5) {
      Console.WriteLine("5以下です");
    }
  }
}
実行結果
5より大きい

言葉で説明するのは難しいので、上記コードを手元の実行環境にコピーして、aの値を色々と変えてみて実験してみましょう。

構文
if-stmt := if '(' 条件式 ')' 文1 [ else 文2 ]
条件式は、bool型である必要があります[1]
文は、Console.WriteLine("5より大きい");のような単文のほか、複文(ブロック; block)も含まれます(ここに示した例はすべて複文です)。
複文とは、if文の直後の{から次の}までにある、区画(英語でブロック)の処理のことです。
if文のあとにelse ifを使うと[2]、直前のif文が実行されなかった場合にだけ条件判定させることができます。下記のように使います。
else節のあるif文の例
using System;

public class Hello {
  public static void Main(string[] args) {
    int a = +2;

    if (a > 5) {
      Console.WriteLine("5より大きい");
    } else if (a >= 0 && a <= 5) {
      Console.WriteLine("0以上かつ5以下です");
    } else {
      Console.WriteLine("0未満です");
    }
  }
}
実行結果
0以上かつ5以下です

else if で判定が行われる条件として直前のif文が満たされなかった場合でなければなりません。なので、もし直前のif文が満たされるように条件を書き換えると、else if は実行されなくなります。試してみましょう。

下記コードは、やや条件分岐のバグを含んでいます。

条件分岐にバグあり
using System;

public class Hello {
  public static void Main(string[] args) {
    int a = +2;

    if (a < 5) { // 不等号を逆に書き換えた
      Console.WriteLine("5より大きい");
    } else if (a >= 0 && a <= 5) {
      Console.WriteLine("0以上かつ5以下です");
    } else {
      Console.WriteLine("0未満です");
    }
  }
}
実行結果
5より大きい
「0以上かつ5以下」という条件は満たしているのにもかかわらず、else if の直前のif文が満たされているので、else if のブロックは実行されていません。
この例のように、else if は、なれずに使うとバグにつながります。elseの仕組みを正しく理解して、どうしても必要な場合にだけ else ifelse を使いましょう。
当然ですが、直前にif がないのに else if を使うとエラーになります。
また、直前が else で終わってるのに続けてelse if を使ってもエラーになります。
また、ifelseelse if のあいだに Console.WriteLine(a);など別の文があってもエラーになります。

単なるswitch文編集

まず、switch文やenumはC#では下記のように使う。.net core 6 で下記コードが動くので、C#10 に対応しているはず。

switch文についての説明は省略する。2022年6月現在、まだ当wikiにC#のif文やswitch文の教材は無いので、標準Cなどの解説を参照してもらいたい。

※ 下記は .net core でのプログラム

using System;

week weekinst = week.Saturday;

switch (weekinst) {

case week.Saturday:
    Console.WriteLine("土曜日");
    break;
case week.Sunday:
    Console.WriteLine("日曜日");
    break;

default:
    Console.WriteLine("平日");
    break;
}

enum week { 
  Sunday, 
  Monday, 
  Tuesday, 
  Wednesday, 
  Thursday, 
  Friday, 
  Saturday 
}
実行結果
土曜日


enumについては、後述する列挙型のセクションを参照せよ。

enumを使わなくてもswitch文は書けるが、現代では、なるべくenumを使って書くのが望ましい。


enum を使わない場合、たとえば下記のように、条件を意味する数値をプログラマー側で決めておいて割り当てをしなければならず、色々と問題がある(プログラマーごとの割り当てルールのバラツキの問題、追加で挿入の条件があると以降の番号を振り直しの問題、など)。

using System;

public class Hello {
  public static void Main(string[] args) {

    
    const int Saturday = 0;
    const int Sunday = 1;
    const int Monday = 2;
    const int Tuesday = 3;
    // 長いので省略

var weekinst = Monday; // とりあえず月曜日

switch (weekinst) {

case Saturday:
    Console.WriteLine("土曜日");
    break;
case Sunday:
    Console.WriteLine("日曜日");
    break;
case Monday:
    Console.WriteLine("月曜日");
    break;
default:
    Console.WriteLine("火曜から金曜");
    break;
}

  }
}
実行結果
月曜日

もしenumを使わないと、たとえば「月曜日(Monday)を0にして数え始めたい」とか顧客の要望などが変わった場合、下記コードの部分の番号を振り直しになるのである。このようにenumを使わないと色々と非効率である。

    
    const int Saturday = 0;
    const int Sunday = 1;
    const int Monday = 2;
    const int Tuesday = 3;
    // 長いので省略

switch式編集

C#7~8 から「switch 式」というのが追加された。下記のような処理ができる。

※ 下記は .net core でのプログラム

week weekval = week.Saturday;

string message = weekval switch  {        // switch式用のインスタンス的なものを作成しないといけない

  week.Saturday => "土曜日" ,

  week.Sunday => "日曜日" ,

  _  => "平日" , // default に相当

};

Console.WriteLine(message);


enum week { 
  Sunday, 
  Monday, 
  Tuesday, 
  Wednesday, 
  Thursday, 
  Friday, 
  Saturday 
}
実行結果
土曜日

switch式では条件に「default」は使えない。アンダーバー_で指定した条件以外の値の場合の結果を指定する。

C#のコンパイラでは、switch式の全ての値を網羅してないかぎり、アンダーバー_で指定しないと、警告が出る。よって上記のようなコードになる。

なお、

week.Saturday  =>Console.WriteLine("土曜日"); // エラー

と書いても、うまく行かない。コンパイラにvoid型に変換できないと出るが、しかし

void message = weekval switch  { // エラー   

などと書き換えてもエラーになる。

よって、上記コードのように、switch式の結果(右側)では、命令ではなく値だけを指定して事前に用意された変数に代入することになる。別途、その結果を代入した変数をつかって目的の処理をする命令が必要である。

列挙型編集

条件分岐に限った機能ではないのですが、 enum というキーワードを使う列挙型(Enumeration types)という機能が標準C言語の時代からあり、C++にもC#にもenumがあります。

enum は下記のように使います。なおコードはMicrosoft Doc のものを『列挙型 (C# リファレンス)』2022/04/06、当wikiで紹介した実行環境でも動くように修正したものです。

※ 下記は .net framework および mono のコード

using System;

public enum Season {
  Spring,
  Summer,
  Autumn,
  Winter
}

public class EnumConversionExample {
  public static void Main() {
    Season a = Season.Autumn;
    Console.WriteLine($ "Integral value of {a} is {(int)a}"); // output: Integral value of Autumn is 2

    var b = (Season) 1;
    Console.WriteLine(b); // output: Summer

    var c = (Season) 4;
    Console.WriteLine(c); // output: 4
  }
}
実行結果
Integral value of Autumn is 2
Summer
Winter


まず、C# の enum は、特にクラスで包含する必要はありません。このように enum はC#では特殊なクラスのようなものとして扱われています。

enum は、定数のグループを作るためのものであり、ブロック内での定数の宣言順に 0,1,2,3,・・・の定数値を割り当てするものです。なんのためにこれをするかというと、用途は多々考えられますが、よくswitch文への応用が挙げられます。

ともかく、enum は広い意味でのクラスの一種なので、要素へのアクセス方法も、Season.Autumnのように

enum型名.変数名

です。なお、enumの要素のことをプログラミング一般で「列挙子」とか「列挙定数」と言います。つまり、

public enum 列挙型名 {
    列挙子名0,
    列挙子名1,
    列挙子名2,
    列挙子名3
}

です。

広い意味でのクラスの一種と言いましたが、しかしenumはC#よりも昔からあることもあってか、newなどのキーワードによるインスタンスの作成は不要です。そもそも書き換えをしないので、インスタンスの作成は不要です(インスタンスは呼び出し元ごとに書き換えをしたりアレンジしたりするためのものだから)。

c# の enum の場合、var b = (Season)1; をenum型名でキャストすることで、割り当て数値→列挙子名への逆引きができます。

ですが、列挙子に割り当てられてないものをキャストしようとした場合、そのまま数値が変えされます。割り当てられてない数値が与えられても、そこでプログラムが止まったりはしません。


c++では、c++11 から enum型とは別に enum class という仕様がありますが、C# にenum class は知られておらず、無いものと思われます。

c++ の enum class はアクセス時に列挙子名だけでなく型名も必要になることでenum列挙子のグローバル変数化を防ぐというためのものなのです。C#ではenumの仕様の最初から列挙型名もアクセスに必要なので、列挙型のままで問題ないのも、理由のひとつでしょう。

脚註編集

  1. ^ int 型などを条件式に書くとエラーになります。C#では、0を偽とはみなしません。i != 0の様に明示的に比較演算子を使いましょう
  2. ^ else if は、文法的には else節の文2が内包されるif文となったと解されます。その後のelseは直近のifと結合します。