C#の「if文」と「if-else文」とは、特定の条件によって処理を分岐させる、「条件分岐」を行うためのステートメント(構文)です。たとえば、「条件Aを満たすときは処理Xを行う」「条件Bを満たさない場合は処理Yを行う」など、条件に応じて処理を分岐させたい場面は常に登場します。
if文やif-else文を使うと、さまざまな条件に臨機応変に対応できるプログラムが書けます。しかし、条件分岐処理を使いこなすためには、「論理演算子」や「条件演算子」と、その評価結果である「真偽値(trueとfalse)」について理解しておくことが重要です。そこで本記事では、C#のif文やif-else文の使い方と応用テクニックを、サンプルコード付きで解説します。
目次
C#の「if文」と「if-else文」は、特定の条件によって処理を分岐させる、「条件分岐」を行うためのステートメント(構文)です。たとえば、「条件Aを満たすときは処理Xを行う」「条件Bを満たさない場合は処理Yを行う」など、条件に応じて処理を分岐させたい場面は常に登場します。
if文を使うことで、たとえば以下のサンプルコードのように、ユーザーが入力した数値が偶数か奇数かによって処理を分けることが可能です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る int number = Input(); // 入力値が偶数であれば「偶数です」と表示する if(number % 2 == 0) { Console.WriteLine(number + "は偶数です!"); } // 偶数でなければ「奇数です」と表示する else { Console.WriteLine(number + "は奇数です!"); } } // ユーザーに整数値を入力してもらうメソッド(今回は重要ではない部分です) public static int Input() { int result; string input; do { // ユーザーに整数値の入力を求める Console.Write("整数値を入力してください:"); input = Console.ReadLine(); } while (!Int32.TryParse(input, out result)); return result; } } }
//実行結果
上記のサンプルプログラムでは、ユーザーの入力値が偶数か奇数かによって、画面上に表示する内容を変えています。ちなみに偶数か奇数かの判定は、「2で割った余りが0」であれば偶数・そうでなければ奇数とすれば大丈夫です。Inputメソッドの内容は今回の本題ではないため、とくに理解しておく必要はありません。
このようにC#のプログラミングでは、状況に応じて処理を変える「条件分岐」が必要な場面が多々あります。if文・if-else文を活用すると、あらゆる場面に対応できるコーディングができるようになり、多様なプログラムが作れるようになるでしょう。
if文・if-else文の基本的な書き方について、以下3つのポイントに分けて解説します。
C#のif文は「Aの場合はBの処理を行う」ことを示し、以下の構文で書きます。
if (条件式) { 条件式が満たされた場合の処理内容; }
if文で最も重要な部分は、「条件式は結果が『真偽値』になる式を記載すること」です。真偽値については後述しますが、「真(true)」もしくは「偽(false)」で示される値を指します。つまり、if文の中身には「条件式がtrueの場合に行いたい処理」を書くということです。
たとえば以下のサンプルプログラムでは、ユーザーが入力した文字数に応じて、画面上に表示するメッセージを変更しています。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーに文字か文字列の入力を求める Console.Write("「文字」か「文字列」を入力してください:"); string input = Console.ReadLine(); // 1文字以下の場合は「文字が入力されました」と表示する if (input.Length <= 1) { Console.WriteLine("文字が入力されました!"); } // 2文字以上の場合は「文字列が入力されました」と表示する if (input.Length >= 2) { Console.WriteLine("文字列が入力されました!"); } } } }
//実行結果
「文字」か「文字列」の2種類を判別するために、2つのif文を用いて「input」変数の長さによって、処理を条件分岐させていることがポイントです。
if文は「条件を満たした場合に行う処理」を書くためのものですが、その直後に「満たさない場合の処理」を書きたい場合は「else文」を使います。else文の構文は以下のとおりです。
if (条件式) { 条件式が満たされた場合の処理内容; } else { 条件式が満たされない場合の処理内容; }
構文自体は単純で、先ほどのif文のすぐ下に「else」と書くだけです。ただし、if文とは異なり条件式は書かず、if文の条件式の結果が「偽(false)」になる処理を書くことが重要です。
先ほどのサンプルコードは、if文が2つ並んでいるため冗長でした。これをif-else文を使うと、以下のように簡潔にコードを書くことができます。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーに文字か文字列の入力を求める Console.Write("「文字」か「文字列」を入力してください:"); string input = Console.ReadLine(); // 1文字以下の場合は「文字が入力されました」と表示する if (input.Length <= 1) { Console.WriteLine("文字が入力されました!"); } // 2文字以上の場合は「文字列が入力されました」と表示する else { Console.WriteLine("文字列が入力されました!"); } } } }
//実行結果
「文字」と「文字列」の違いは、長さが1以下かそうでないかの違いになります。したがって、if文の条件式「input.Length <= 1」を満たさないものは、自動的に文字列だということになるため、それをelse文の中に書けば完了です。
分岐させたい処理は必ずしも「2択」とは限らず、複数パターンの条件分岐を行いたいこともあります。その場合は「else-if文」を使って、新たな条件式を記載して、細かな条件分岐を行います。else-if文の構文は以下のとおりです。
if (条件式1) { 条件式1が満たされた場合の処理内容; } else if (条件式2) { 条件式1が満たされず、条件式2が満たされる場合の処理内容; } else if (条件式3) { 条件式1と条件式2が満たされず、条件式3が満たされる場合の処理内容; } else { すべての条件式が満たされない場合の処理内容; }
上記のように、else-if文はいくらでも繋げることができます。ただし重要なポイントは、「else-if文の中身は、最初のif文がfalseでなければ実行されない」ということです。つまり一連のif文は、前から順番に評価されていって、trueになるものがあれば以降の部分はスキップされるということです。
以下のサンプルコードでは、これまでの2択に「未入力」の条件分岐も加えて、3択のif文にしました。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーに文字か文字列の入力を求める Console.Write("「文字」か「文字列」を入力してください:"); string input = Console.ReadLine(); // 0文字の場合は「何も入力されませんでした」と表示する if (input.Length == 0) { Console.WriteLine("何も入力されませんでした!"); } // 1文字の場合は「文字が入力されました」と表示する else if (input.Length == 1) { Console.WriteLine("文字が入力されました!"); } // それ以外の場合は「文字列が入力されました」と表示する else { Console.WriteLine("文字列が入力されました!"); } } } }
//実行結果
入力された文字列の長さが「0」であれば空入力、「1」なら文字になり、それ以外つまり「2以上」の場合は文字列となります。このように、if文・if-else文・else if文を活用すると、さまざまな条件分岐ができるようになるでしょう。
C#のif文を書くためには「条件式」を記載する必要がありますが、そのためには特定の要素との「比較」を行わないといけません。たとえば、「Aより大きい場合」「Bより小さい場合」「Cと等しい場合」など、あらゆる条件式は何かと比較する必要があります。
そのために使用するのが「比較演算子」です。比較演算子とは、左辺と右辺との比較を行い、その結果を「真(true)」もしくは「偽(false)」で評価する演算子のこと。比較演算子には以下6つの種類があります。
比較演算子 | 書き方・使い方 | 意味 |
---|---|---|
== | a == b | aはbと等しい |
!= | a != b | aはbと等しくない |
< | a < b | aはbより小さい |
> | a > b | aはbより大きい |
<= | a <= b | aはb以下 |
>= | a >= b | aはb以上 |
ここで重要なポイントは、どの演算子も結果は真偽値、つまり「true(真)」もしくは「false(偽)」で返るということです。比較演算子を使って、実際にif文でさまざまな値を比較してみましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る int numA = Input(1); int numB = Input(2); Console.WriteLine(); // numAがnumBと等しいか if (numA == numB) { Console.WriteLine("numAはnumBと等しい"); } // numAがnumBと等しくないか if (numA != numB) { Console.WriteLine("numAはnumBと等しくない"); } // numAがnumBより小さいか if (numA < numB) { Console.WriteLine("numAはnumBより小さい"); } // numAがnumBより大きいか if (numA > numB) { Console.WriteLine("numAはnumBより大きい"); } // numAがnumB以下か if (numA <= numB) { Console.WriteLine("numAはnumB以下"); } // numAがnumB以上か if (numA >= numB) { Console.WriteLine("numAはnumB以上"); } Console.WriteLine(); // 真偽値一覧を表示 Console.WriteLine("numA == numB ⇒ " + (numA == numB)); Console.WriteLine("numA != numB ⇒ " + (numA != numB)); Console.WriteLine("numA < numB ⇒ " + (numA < numB)); Console.WriteLine("numA > numB ⇒ " + (numA > numB)); Console.WriteLine("numA <= numB ⇒ " + (numA <= numB)); Console.WriteLine("numA >= numB ⇒ " + (numA >= numB)); } // ユーザーに整数値を入力してもらうメソッド(今回は重要ではない部分です) public static int Input(int count) { int result; string input; do { // ユーザーに整数値の入力を求める Console.Write(count + "つ目の整数値を入力してください:"); input = Console.ReadLine(); } while (!Int32.TryParse(input, out result)); return result; } } }
//実行結果
2つの整数値を入力すると、先ほどご紹介した6つの比較演算子すべてを使って、2つの値を比較します。比較演算子の結果がtrueになったものを表示し、最後に6つの評価結果すべてをtrueとfalseで表示しています。さまざまな値を入力して、どのような場合に比較演算子の結果が、trueもしくはfalseになるかチェックしてみましょう。
複数の条件が真(true)のときに処理を行いたい場合は、以下のように、「if文の中にさらにif文を加える」のがひとつの方法です。
if (条件式1) { if (条件式2) { 条件式1と条件式2の両方が満たされる場合の処理内容; } else { 条件式1が満たされたが、条件式2が満たされない場合の処理内容; } } else { 条件式1が満たされない場合の処理内容; }
上記のように、単純にif文の中にif文・if-else文を書けば、複数の条件式を適用した条件分岐が書けます。このような書き方を「ネスト(入れ子)」と呼びます。if文をネストさせる場合のサンプルコードを確認していきましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る int numA = Input(1); int numB = Input(2); // numAが偶数の場合 if (numA % 2 == 0) { if (numB % 2 == 0) { Console.WriteLine("どちらの値も偶数です"); } else { Console.WriteLine("一方の値が偶数です"); } } // numAが奇数の場合 else { if (numB % 2 == 0) { Console.WriteLine("一方の値が偶数です"); } else { Console.WriteLine("どちらの値も偶数ではありません"); } } } // ユーザーに整数値を入力してもらうメソッド(今回は重要ではない部分です) public static int Input(int count) { int result; string input; do { // ユーザーに整数値の入力を求める Console.Write(count + "つ目の整数値を入力してください:"); input = Console.ReadLine(); } while (!Int32.TryParse(input, out result)); return result; } } }
//実行結果
if文を「ネスト(入れ子)」にすると、複数の条件を満たす場合のみに処理を分岐させることができます。一方で「論理演算子」を使えば、以下のようにもっとシンプルになります。
//サンプルプログラム // 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る int numA = Input(1); int numB = Input(2); // どちらも偶数の場合 if (numA % 2 == 0 && numB % 2 == 0) { Console.WriteLine("どちらの値も偶数です"); } // どちらか一方が偶数の場合 else if (numA % 2 == 0 || numB % 2 == 0) { Console.WriteLine("どちらか一方の値が偶数です"); } // どちらも偶数ではない場合 else { Console.WriteLine("どちらも偶数ではありません"); } } // ユーザーに整数値を入力してもらうメソッド(今回は重要ではない部分です) public static int Input(int count) { int result; string input; do { // ユーザーに整数値の入力を求める Console.Write(count + "つ目の整数値を入力してください:"); input = Console.ReadLine(); } while (!Int32.TryParse(input, out result)); return result; } } }
if文のネストがなくなったことにより、if文の数が減って簡潔になりました。C#のプログラミングでは、ソースコードをわかりやすく書くために、論理演算子を使うことが多いです。論理演算子の書き方と使い方については、このあと詳しくご紹介します。
C#のif文の条件式を書くときは、「論理演算」が必要な場面がたまに登場します。その際に特に重要な、以下4つの論理演算の知識について解説します。
「論理積(AND)」は、双方の真偽値が「真」のときだけ「真」になる論理演算です。2つの条件式の論理演算を行ったとき、それぞれの真偽値によって結果が以下のように異なります。
1つ目の条件式の結果 | 2つ目の条件式の結果 | 論理演算の結果 |
---|---|---|
true | true | true |
true | false | false |
false | true | false |
false | false | false |
たとえば「aが偶数でbが奇数」の場合、「a == 偶数」と「b == 偶数」という条件式の論理積(AND)は「偽(false)」となります。この2つの条件式では、「aとbの双方が偶数」でなければ結果は「真(true)」になりません。
「論理和(OR)」は、どちらかの真偽値が「真」であれば「真」になる論理演算です。2つの条件式の論理演算を行ったとき、それぞれの真偽値によって結果が以下のように異なります。
1つ目の条件式の結果 | 2つ目の条件式の結果 | 論理演算の結果 |
---|---|---|
true | true | true |
true | false | true |
false | true | true |
false | false | false |
たとえば「aが偶数でbが奇数」の場合、「a == 偶数」と「b == 偶数」という条件式の論理和(OR)は「真(true)」となります。この2つの条件式では、「aとbの双方が偶数」「aが奇数でbが偶数」の場合も結果が「真(true)」になることを覚えておいてください。
「否定論理積(NAND)」は、双方の真偽値が「真」以外のとき「真」になる論理演算です。2つの条件式の論理演算を行ったとき、それぞれの真偽値によって結果が以下のように異なります。
1つ目の条件式の結果 | 2つ目の条件式の結果 | 論理演算の結果 |
---|---|---|
true | true | false |
true | false | true |
false | true | true |
false | false | true |
たとえば「aが偶数でbが奇数」の場合、「a == 偶数」と「b == 偶数」という条件式の否定論理積(NAND)の結果は、「a != 偶数」と「b != 偶数」の論理和(OR)の結果と同じになります。つまり、2つの値のいずれかが奇数であれば、その結果は「真(true)」になるということです。
「否定論理和(NOR)」は、双方の真偽値が「偽」のときに「真」になる論理演算です。2つの条件式の論理演算を行ったとき、それぞれの真偽値によって結果が以下のように異なります。
1つ目の条件式の結果 | 2つ目の条件式の結果 | 論理演算の結果 |
---|---|---|
true | true | false |
true | false | false |
false | true | false |
false | false | true |
たとえば「aが偶数でbが奇数」の場合、「a == 偶数」と「b == 偶数」という条件式の否定論理積(NAND)の結果は、「a != 偶数」と「b != 偶数」の論理積(AND)の結果と同じになります。つまり、2つの値の双方が奇数の場合のみ、その結果が「真(true)」にならないということです。
C#で複数の条件を満たした場合のみに処理を行いたい場合、2つ目の方法が「論理演算子」を使うというものです。論理演算子は、先ほど解説した論理演算を行うための演算子で、主に以下3種類の演算子がよく使われます。
論理演算子 | 書き方・使い方 | 意味 |
---|---|---|
&& | a && b | 論理積(AND)aとbの条件がどちらも成立するか |
|| | a || b | 論理和(OR)aとbの条件のいずれかが成立するか |
! | !X | Xの否定(NOT)Xがtrueの場合はfalseにfalseの場合はtrueになる |
先ほどの比較演算子と同じように、論理演算の結果は真偽値、つまり「true(真)」もしくは「false(偽)」で返ります。なお、否定論理積(NAND)と否定論理和(NOR)については、以下のように表現されます。
論理演算 | 書き方・使い方 | 備考 |
---|---|---|
否定論理積(NAND) | ! (a && b) | 「!a || !b」と同じ |
否定論理和(NOR) | ! (a || b) | 「!a && !b」と同じ |
これらの論理演算子を活用して、実際にif文でさまざまな値の論理演算を行ってみましょう。サンプルコードは以下のとおりです。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る int numA = Input(1); int numB = Input(2); Console.WriteLine(); // numAとnumBの双方が偶数か if ((numA % 2 == 0) && (numB % 2 == 0)) { Console.WriteLine("numAとnumBの双方が偶数"); } // numAとnumBのどちらか一方が偶数か if ((numA % 2 == 0) || (numB % 2 == 0)) { Console.WriteLine("numAとnumBのどちらか一方が偶数"); } // 「numAとnumBの双方が偶数」ではない状態か // ⇒ numAとnumBのどちらか一方が奇数か if (!((numA % 2 == 0) && (numB % 2 == 0))) { Console.WriteLine("numAとnumBのどちらか一方が奇数"); } // 「numAとnumBのどちらか一方が偶数」ではない状態か // ⇒ numAとnumBの双方が奇数か if (!((numA % 2 == 0) || (numB % 2 == 0))) { Console.WriteLine("numAとnumBの双方が奇数"); } Console.WriteLine(); // 真偽値一覧を表示 Console.WriteLine(" (numA % 2 == 0) && (numB % 2 == 0) ⇒ " + ( (numA % 2 == 0) && (numB % 2 == 0))); Console.WriteLine(" (numA % 2 == 0) || (numB % 2 == 0) ⇒ " + ( (numA % 2 == 0) || (numB % 2 == 0))); Console.WriteLine("!((numA % 2 == 0) && (numB % 2 == 0)) ⇒ " + (!((numA % 2 == 0) && (numB % 2 == 0)))); Console.WriteLine("!((numA % 2 == 0) || (numB % 2 == 0)) ⇒ " + (!((numA % 2 == 0) || (numB % 2 == 0)))); } // ユーザーに整数値を入力してもらうメソッド(今回は重要ではない部分です) public static int Input(int count) { int result; string input; do { // ユーザーに整数値の入力を求める Console.Write(count + "つ目の整数値を入力してください:"); input = Console.ReadLine(); } while (!Int32.TryParse(input, out result)); return result; } } }
//実行結果
2つの整数値を入力すると、先ほどご紹介した4つの論理演算すべてを行い、2つの値の関連性を評価します。論理演算の結果がtrueになったものを表示し、最後に4つの評価結果すべてをtrueとfalseで表示しています。さまざまな値を入力して、どのような場合に論理演算の結果が、trueもしくはfalseになるかチェックしてみましょう。
C#では「bool値」を直接的にif文の条件式に使うこともできます。bool値とは真偽値、つまり「true」もしくは「false」のいずれかの値です。これまで見てきたif文の条件式も、最終的には真偽値・bool値で評価されます。以下のサンプルプログラムのように、状況によってはbool値をif文の条件式に直接指定すると便利です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した整数値を受け取る Console.Write("整数値を入力してください:"); string input = Console.ReadLine(); // 整数値に変換できるかチェックする int result; bool isInteger = Int32.TryParse(input, out result); // 整数値でなければエラーを表示する if (!isInteger) { Console.WriteLine("入力された数値は整数値ではありません"); } else { Console.WriteLine("入力された整数値は" + result + "です"); } } } }
//実行結果
上記のサンプルコードでは、ユーザーが整数値を入力したかどうか、「TryParseメソッド」を使って調べています。TryParseメソッドの戻り値はbool型、つまりtrueかfalseです。if文の条件式は、「if (isInteger == false)」と書くこともできますが、isInteger自体がbool値なので、それを否定して「if (!isInteger)」と書くほうが簡潔です。
また以下のように、bool値は「フラグ」として活用して、条件演算子と組み合わせて条件分岐を行うこともあります。
if ((flagA && !flagB) || flagC) { // 以下略... }
これまでは主に「整数値」に的を絞って、C#のif文による条件分岐を解説してきましたが、それ以外のさまざまなデータ型の条件分岐も見ていきましょう。
float型の条件分岐もint型と同じで、基本的には比較演算子で行うことができます。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーが入力した浮動小数点値を受け取る float numA = Input(1); float numB = Input(2); // 数値を比較する if (numA == numB) { Console.WriteLine(numA + "と" + numB + "は同じです"); } else if (numA < numB) { Console.WriteLine(numA + "は" + numB + "より小さいです"); } else { Console.WriteLine(numA + "と" + numB + "より大きいです"); } } // ユーザーに浮動小数点値を入力してもらうメソッド(今回は重要ではない部分です) public static float Input(int count) { float result; string input; do { // ユーザーに浮動小数点値の入力を求める Console.Write(count + "つ目の浮動小数点値を入力してください:"); input = Console.ReadLine(); } while (!Single.TryParse(input, out result)); return result; } } }
//実行結果
ただし後述するように、floatやdoubleのような浮動小数点値には誤差があるため、条件分岐のやり方によっては意図した動作にならないこともあります。したがって、浮動小数点値の条件分岐には注意が必要です。
文字列を扱うstring型の条件分岐は、これまでのデータ型とは異なり、比較演算子は「==」と「!=」しか使えません。一方で、「string.Compareメソッド」を使えば、文字列同士の「辞書的な並び順」を比較できます。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーからの入力を受け取る Console.Write("1つ目の文字列を入力してください:"); string strA = Console.ReadLine(); Console.Write("2つ目の文字列を入力してください:"); string strB = Console.ReadLine(); // 文字列が等しいかどうかを比較する if (strA == strB) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "と同じです"); } Console.WriteLine(); // 文字列同士の辞書的な並び順を比較する if (string.Compare(strA, strB) == 0) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "と同じです"); } else if (string.Compare(strA, strB) < 0) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "より辞書的に前にあります"); } else { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "より辞書的に後にあります"); } } } }
//実行結果
なお「大文字」と「小文字」を区別せずに比較したい場合は、string.Compareメソッドの第3引数に「true」を渡します。もしくは「名前付き引数」の機能を使い、以下のサンプルコードのように「ignoreCase: true」と記載すると、さらにわかりやすくなります。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーからの入力を受け取る Console.Write("1つ目の文字列を入力してください:"); string strA = Console.ReadLine(); Console.Write("2つ目の文字列を入力してください:"); string strB = Console.ReadLine(); // 文字列が等しいかどうかを比較する if (strA == strB) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "と同じです"); } Console.WriteLine(); // 文字列同士の辞書的な並び順を比較する if (string.Compare(strA, strB, ignoreCase: true) == 0) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "と同じです"); } else if (string.Compare(strA, strB, ignoreCase: true) < 0) { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "より辞書的に前にあります"); } else { Console.WriteLine("「" + strA + "」は「" + strB + "」" + "より辞書的に後にあります"); } } } }
//実行結果
ちなみに「名前付き引数」とは、引数に注釈のように名前を付けることができる機能です。名前付き引数に関する詳細解説は割愛しますが、呼び出し時に引数の順序を変更しても動作するなど、いろいろ便利なことがあります。
配列やクラスなどのオブジェクト型も、基本データ型とは異なり、比較演算子は「==」と「!=」しか使えません。また、オブジェクト型の変数には「実体(値)」ではなく「参照(アドレス)」が入っているため、基本的には比較演算子は「nullチェック」でしか使いません。詳細を以下のサンプルコードで確認してみましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { Object objA = new Object(); Object objB = new Object(); // 2つのオブジェクト変数には参照値(アドレス)が格納されているため // 同じクラスのインスタンスで、実体の値が同じである場合でも // 比較演算子を使うと「等しくない」と判定される if (objA == objB) { Console.WriteLine("objAはobjBと同じです"); } else { Console.WriteLine("objAはobjBと違います"); } // 要素数10のString型配列を生成 String[] data = new String[10]; // 適当なデータを格納していく for (int i = 0; i < data.Length; i++) { data[i] = new String(i.ToString()); } // 「テスト」に該当する要素を検索する // ただし該当する要素がないため「nullオブジェクト」が返る String find = Array.Find(data, p => p == "テスト"); // そのままアクセスすると「NullReferenceException」例外が発生するため // 事前にNullチェックを行ってからアクセスする if (find != null) { // 適当なメソッドにアクセス Console.WriteLine(find.ToLower()); } else { Console.WriteLine("該当するオブジェクトは存在しません"); } } } }
//実行結果
コレクションの「Findメソッド」は、該当するオブジェクトがない場合に「Nullオブジェクト」を返す仕様になっています。そのままアクセスすると「NullReferenceException」例外が発生してしまうため、事前にif文でNullチェックを行ってから、オブジェクトにアクセスする必要があります。
C#では、クラスのインスタンスを基底クラス(スーパークラス)にキャスト(型変換)できます。とくに、すべてのクラスは「Objectクラス」のスーパークラスであるため、インスタンス化したクラスを以下のようにObject型変数に格納できます。
Object obj = new String("");
しかし、元のクラスに戻すときは正しいデータ型にキャストする必要があり、誤った型に変換すると「InvalidCastException」が発生します。そのため、キャスト時は正しいデータ型を指定する必要があるのですが、元の型が確実にわからない場合は「型チェック」が必要です。本章では、if文を使った安全なキャスト方法を3つご紹介します。
C#で安全なキャスト(型変換)を行うひとつの方法が、if文で「GetTypeメソッド」と「typeof演算子」を使って分岐させるというものです。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // String型のインスタンスをObject型変数に格納する Object obj = new String("Test"); // 「GetTypeメソッド」と「typeof演算子」で元のデータ型に変換する if (obj.GetType() == typeof(String)) { // 実際にキャストして、すべての文字を大文字に変換して表示する String str = (String)obj; Console.WriteLine(str.ToUpper()); } } } }
//実行結果
上記のサンプルプログラムは何の問題もなく動きます。ただしこの方法では、「変数宣言時の型」を指定した場合しか、if文の条件式がtrueになりません。たとえば以下のサンプルコードで示すように、「基底クラス」は認識されないので注意が必要です。
//サンプルプログラム // 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { // 親クラス public class Parent { } public class Child : Parent { } public class GrandChild : Child { } public class GreatGrandChild : GrandChild { } public class Program { public static void Main() { // GreatGrandChild型のインスタンスをObject型変数に格納する Object obj = new GreatGrandChild(); // 型変換できるかどうかをチェックする Console.WriteLine(obj.GetType() == typeof(Parent)); Console.WriteLine(obj.GetType() == typeof(Child)); Console.WriteLine(obj.GetType() == typeof(GrandChild)); Console.WriteLine(obj.GetType() == typeof(GreatGrandChild)); // 型変換する Parent parent = (Parent)obj; Child child = (Child)obj; GrandChild grandChild = (GrandChild)obj; GreatGrandChild greatGrandChild = (GreatGrandChild)obj; } } }
//実行結果
上記のサンプルプログラムでは、継承関係にある4つのクラスを生成し、先ほどと同じように「GetTypeメソッド」と「typeof演算子」を使って、キャストできるかどうか判定しました。その結果は、「GreatGrandChildクラス」のみにキャスト可能で、ほかの基底クラスには型変換できないというものです。
これは、obj変数をGreatGrandChild型で生成していることが理由です。しかし実際には、サンプルコード後半のようにほかのスーパークラスにキャストしても、「InvalidCastException」は発生しません。これはC#の仕様上、仕方がありません。言い換えれば、この方法では正確な型判定が行えないケースもあるということです。
「is演算子」と「as演算子」を使うと、より簡潔で正確な型チェックとキャストができるようになります。is演算子の構文は以下のとおりです。
if (変換元の変数 is 変換先のデータ型) { 変換先のデータ型 変換先の変数 = 変換元の変数 as 変換先のデータ型; }
たとえばString型変数「str」をObject型変数「obj」に格納したあと、元のString型に戻したい場合は、「if (obj is String)」としたあとに「String str = obj as String」すると、if文の中でString型の「str」が使えるようになります。詳細を以下のサンプルコードで確認しましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // String型のインスタンスをObject型変数に格納する Object obj = new String("Test"); // 「is演算子」で元のデータ型に変換する if (obj is String) { // 実際にキャストして、すべての文字を大文字に変換して表示する String str = obj as String; Console.WriteLine(str.ToUpper()); } } } }
//実行結果
先ほどの方法とは異なり、以下のように基底クラスを指定した場合でも、問題なく判定できるので、さまざまな場面で活用できます。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { // 親クラス public class Parent { } public class Child : Parent { } public class GrandChild : Child { } public class GreatGrandChild : GrandChild { } public class Program { public static void Main() { // GreatGrandChild型のインスタンスをObject型変数に格納する Object obj = new GreatGrandChild(); // 型変換できるかどうかをチェックする Console.WriteLine(obj is Parent); Console.WriteLine(obj is Child); Console.WriteLine(obj is GrandChild); Console.WriteLine(obj is GreatGrandChild); // 型変換する Parent parent = (Parent)obj; Child child = (Child)obj; GrandChild grandChild = (GrandChild)obj; GreatGrandChild greatGrandChild = (GreatGrandChild)obj; } } }
//実行結果
上記のように、変数宣言時の型名だけではなく、そのスーパークラスにもキャストできると判定されます。これはC#の実態と一致するため、非常に正確な手法だといえるでしょう。
さらに、現在のC#ではis演算子の「パターンマッチング」が利用できて、as演算子を使わなくても以下の構文で型チェックとキャストが同時に行えます。
if (変換元の変数 is 変換先のデータ型 変換先の変数) { // 型チェックとキャストが同時に行える! }
先ほどはif文で型チェックを行ってから、as演算子で実際にキャストするという流れでした。is演算子の「パターンマッチング」を使うと、以下のサンプルコードのようにさらに簡潔な型キャストができます。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // String型のインスタンスをObject型変数に格納する Object obj = new String("Test"); // 「is演算子」で元のデータ型に変換する if (obj is String str) { Console.WriteLine(str.ToUpper()); } } } }
//実行結果
先ほどの方法と同じく、もちろん基底クラスも問題なく判定できます。C#のオブジェクトをキャストするときは、基本的にこの方法を活用するといいでしょう。
C#のif文・if-else文を使うときに意識すべき注意点は以下4つです。
条件式は「bool型」でないといけません。C言語やC++を学んだことがある人は、以下のようなコードを書かないよう注意してください。
//サンプルプログラム
namespace Main { public class Program { public static void Main() { // 適当な変数を生成する int data = 1; int[] array = new int[10]; // dataはint型であるため、if文の条件式には使えない if (data) { // 省略 } // arrayは参照型であるため、if文の条件式には使えない if (array) { // 省略 } } } }
C言語やC++では、上記のコードが動きます。なぜなら0は「false」に、0以外の値は「true」へ暗黙的に変換されるからです。さらに、C#の参照型に相当する「ポインタ型」は、nullポインタがfalseに、それ以外がtrueに暗黙的に変換されます。C#は型に厳格なので、こうした暗黙的な変換は行われません。
C#の演算子には「優先順位」があるため、これを理解しておかないと意図したとおりの条件分岐ができません。たとえば以下のサンプルコードでは、プログラマーが意図しない動作になる可能性があります。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // 適当な変数を生成する int a = 0; int b = 2; // プログラマーは「a == 0 もしくは a == 1」かつ「b == 0 もしくは b == 1」を意図 // つまり、aとbはともに「0」か「1」でなくてはならない if (a == 0 || a == 1 && b == 0 || b == 1) { // しかし、実際には「a == 0」もしくは「a == 1 かつ b == 0」もしくは「b == 1」 // と解釈されるため、「a == 0」もしくは「b == 1」であれば成立してしまう Console.WriteLine("パターン1は条件成立!"); } else { Console.WriteLine("パターン1は不成立…"); } // 適当なフラグを生成する bool b1 = true; bool b2 = false; // プログラマーは「b1 && b2」の否定を意図 // つまり「b1とb2の一方または両方がfalseの場合に実行される」ことを期待している if (!b1 && b2) { // しかし実際には、「b1の否定 && b2」と解釈されるため、 // b1がfalse、b2がtrueでなければ実行されない Console.WriteLine("パターン1は条件成立!"); } else { Console.WriteLine("パターン2は不成立…"); } } } }
//実行結果
2つのパターンともに、プログラマーの意図とは異なる実行結果になりました。その理由は、論理演算子の優先順位が以下のようになっているからです。
つまり「||」の前に「&&」が評価され、さらにその「&&」の前に「!」が評価されるということです。これを意識しておかないと、思わぬバグの原因になるので注意しましょう。これを防ぐためには、以下のように「括弧(カッコ)」を使って、演算の優先結果を明示する必要があります。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // 適当な変数を生成する int a = 0; int b = 2; // プログラマーは「a == 0 もしくは a == 1」かつ「b == 0 もしくは b == 1」を意図 // つまり、aとbはともに「0」か「1」でなくてはならない if ((a == 0 || a == 1) && (b == 0 || b == 1)) { // ここは実行されない Console.WriteLine("パターン1の条件成立!"); } else { Console.WriteLine("パターン1は不成立…"); } // 適当なフラグを生成する bool b1 = true; bool b2 = false; // プログラマーは「b1 && b2」の否定を意図 // つまり「b1とb2の一方または両方がfalseの場合に実行される」ことを期待している if (!(b1 && b2)) { // ここは実行される Console.WriteLine("パターン2の条件成立!"); } else { Console.WriteLine("パターン2は不成立…"); } } } }
//実行結果
優先させたい論理演算の部分を「括弧(カッコ)」で囲むと、その部分の演算が優先して行われます。そもそも論理演算を並べると見づらくなるため、区切りごとにカッコで囲むクセを付けておくとわかりやすいでしょう。
C#のfloatやdoubleなどの浮動小数点値には、演算によって少しずつ誤差が出ます。そのため以下のように、浮動小数点値とほかの値をif文で比較すると、予期せぬ動作になることがあるので注意が必要です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { float f = 0.0f; // fに0.1ずつ足していって1.0fにする for (int i = 0; i < 10; i++) { f += 0.1f; } // fが1.0fになるかチェックする if (f == 1.0f) { Console.WriteLine("fは1.0です!"); } else { Console.WriteLine("fは1.0ではありません!"); } } } }
//実行結果
上記のサンプルコードでは、0.1を10回足しているため、変数「f」の値は1.0になっているはずです。しかし、実際には1.0になっておらず、デバッグ画面で中身を見てみると「1.00000012」となっています。
これは浮動小数点の仕様により、数値を誤差なく完璧に表現することが難しいからです。したがって、小数点を比較する場合は以下のように、「許容誤差」のマージンを取っておく必要があります。
if (Math.Abs(比較したい数値A - 比較したい数値B) < 0.000001f)
つまり、両者の値を引いてから絶対値を求め、その値が「0.000001f」以下なら同じ値であると判定するということです。このテクニックを活用して、先ほどのサンプルコードを書き直してみましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { float f = 0.0f; // fに0.1ずつ足していって1.0fにする for (int i = 0; i < 10; i++) { f += 0.1f; } // fが1.0fになるかチェックする // ただし許容誤差を0.000001fとする if (Math.Abs(f - 1.0f) < 0.000001f) { Console.WriteLine("fは1.0です!"); } else { Console.WriteLine("fは1.0ではありません!"); } f = 0.0f; // fから0.1ずつ引いていって-1.0fにする for (int i = 0; i < 10; i++) { f -= 0.1f; } // fが-1.0fになるかチェックする // ただし許容誤差を0.000001fとする if (Math.Abs(f - (-1.0f)) < 0.000001f) { Console.WriteLine("fは-1.0です!"); } else { Console.WriteLine("fは-1.0ではありません!"); } } } }
//実行結果
このように問題なく比較判定ができました。上記のサンプルコードでは、念のためにfから0.1fずつ引いていき、「-1.0f」と比較するパターンも行っています。浮動小数点値の比較を行うときは、このように「マージン」を確保するようにしましょう。
C#では、論理積や論理和などの条件判定を行うときに、「ショートサーキット」という仕組みが採用されています。ショートサーキットは、最初の式だけで条件を満たすかどうか決まる場合は、あとの式は評価されないという仕組みです。たとえば以下のようになります。
bool a = true; bool b = false; // この場合は最初の「a」の時点で条件を満たすことがわかるため // あとの「b」は評価されずにif文の中に入る if (a || b) bool c = false; bool d = true; // この場合は最初の「c」の時点で条件を満たさないことがわかるため // あとの「d」は評価されずに条件判定が終わる if (c && d)
ほとんどの場合は、条件判定がショートサーキットであることを意識しなくても、とくに問題は発生しません。しかし以下のように、演算と条件判定を同時に行う場合は、意図しない結果になることがあります。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // 2つの整数値を宣言する int a = 0; int b = 0; // 変数への値の代入と条件判定を同時に行う if ((a = 1) > 0 || (b = -1) < 0) { Console.WriteLine("条件達成!"); } // 2つの変数の中身を表示する Console.WriteLine("aの値:" + a); Console.WriteLine("bの値:" + b); // 変数への値の代入と条件判定を同時に行う if ((a = -1) > 0 && (b = 1) < 0) { Console.WriteLine("条件達成!"); } // 2つの変数の中身を表示する Console.WriteLine("aの値:" + a); Console.WriteLine("bの値:" + b); } } }
//実行結果
最初のif文で、aとbへの代入と条件判定を同時に行っています。if文のあとは「a = 1」で「b = -1」になっていることを期待したいところですが、bには値が代入されていません。これは、ショートサーキットで変数bの条件判定が行われなかったからです。そのあとのif文の同様で、やはりショートサーキットで変数bへの代入が行われていません。
これを防ぐためには、「&&」の代わりに「&」を、「||」の代わりに「|」を使う必要があります。いずれも論理演算子で、基本的な機能は記号を2つ並べる場合と同じですが、1つにするとショートサーキットが行われません。以下のサンプルコードで確認してみましょう。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // 2つの整数値を宣言する int a = 0; int b = 0; // 変数への値の代入と条件判定を同時に行う if ((a = 1) > 0 | (b = -1) < 0) { Console.WriteLine("条件達成!"); } // 2つの変数の中身を表示する Console.WriteLine("aの値:" + a); Console.WriteLine("bの値:" + b); // 変数への値の代入と条件判定を同時に行う if ((a = -1) > 0 & (b = 1) < 0) { Console.WriteLine("条件達成!"); } // 2つの変数の中身を表示する Console.WriteLine("aの値:" + a); Console.WriteLine("bの値:" + b); } } }
//実行結果
上記のように、いかなる場合でも論理演算が省略されることがないため、変数に代入した結果がきちんと反映されています。しかし、そもそも代入と論理演算を同時に行う書き方は見づらいので、個別に書くようにするのがおすすめです。
C#でif文・if-else文以外に条件分岐する方法について、以下4つをご紹介します。
「三項演算子(条件演算子)」は、「?」と「:」の2つの演算子を使って行い、通常のif-else文を1行で書ける機能です。以下の構文のように、3つの項(要素)から成り立つため、三項演算子と呼ばれています。
条件式 ? trueの場合の処理 : falseの場合の処理
三項演算子は、変数に値を代入したり変数の引数として引き渡したりするときに、簡潔な条件分岐ができることが魅力です。詳細を以下のサンプルコードに示すのでご参考ください。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { string str = null; // 通常のif-else文を使う場合 if (str != null) { Console.WriteLine(str); } else { Console.WriteLine("文字列がnullです!"); } // 三項演算子(条件演算子)を使う場合 Console.WriteLine(str != null ? str : "文字列がnullです!"); } } }
//実行結果
if-else文では何行も必要な処理が、わずか1行で書けるのが三項演算子の魅力です。ちなみに、冒頭で紹介したサンプルプログラムも三項演算子を使えばより簡潔になります。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { // ユーザーに文字か文字列の入力を求める Console.Write("「文字」か「文字列」を入力してください:"); string input = Console.ReadLine(); Console.WriteLine("文字" + (input.Length <= 1 ? "" : "列") + "が入力されました!"); } } }
//実行結果
まず共通の「文字」を表示し、1文字以下なら何も追加せず、それ以外なら「列」を追加するというソースコードです。このように処理内容を2択で分岐させたい場合は、三項演算子が使えないか検討してみると、より簡潔なソースコードが書けるようになるのでおすすめです。
「switch-case文」とは、特定の変数の値に応じて、さまざまな条件分岐を行うための機能です。switch-case文の構文は以下のとおりです。
switch (条件分岐に使う変数) { case 値1: 「変数 == 値1」のときの処理内容; break; case 値2: 「変数 == 値2」のときの処理内容; break; case 値3: 「変数 == 値3」のときの処理内容; break; default: 上記のいずれにも該当しない場合の処理内容; break; }
上記のような分岐は、if-else文を使うと非常に長くなってわかりづらいことが難点です。そのため、ひとつの変数の値によって処理を分岐させる場合は、switch-case文を積極的に使うとソースコードが簡潔になります。たとえば以下のサンプルプログラムは、switch-case文を使うべき典型例です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void If(string input) { // 最初のメッセージを作成する string message = "「" + input + "」は"; // 果物の種類によって表示を変更する if (input == "りんご") { message += "赤くて丸いです"; } else if (input == "ばなな") { message += "黄色くて細長いです"; } else if (input == "ぶどう") { message += "紫色で房にたくさん付いています"; } else if (input == "すいか") { message += "緑っぽい色で夏によく見かけます"; } else if (input == "みかん") { message += "橙色で冬によく見かけます"; } else if (input == "もも") { message += "ピンク色で柔らかいです"; } else { message += "よく分からない果物です…"; } // メッセージを表示する Console.WriteLine(message); } public static void Switch(string input) { // 最初のメッセージを作成する string message = "「" + input + "」は"; // 果物の種類によって表示を変更する switch (input) { case "りんご": message += "赤くて丸いです"; break; case "ばなな": message += "黄色くて細長いです"; break; case "ぶどう": message += "紫色で房にたくさん付いています"; break; case "すいか": message += "緑っぽい色で夏によく見かけます"; break; case "みかん": message += "橙色で冬によく見かけます"; break; case "もも": message += "ピンク色で柔らかいです"; break; default: message += "よく分からない果物です…"; break; } // メッセージを表示する Console.WriteLine(message); } public static void Main() { // ユーザーに果物の入力を求める Console.Write("お好きな「果物」を平仮名で入力してください:"); string input = Console.ReadLine(); // if-else文の場合 If(input); // switch-case文の場合 Switch(input); } } }
//実行結果
なお現在のC#では、以下のように「値」だけではなく「型」で分岐させるほか、複数の値で分岐させることも可能です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { static void TypeSwitch(object obj) { // 変数の型によって処理を分岐させる switch (obj) { case int i: Console.WriteLine("整数型 " + i); break; case float f: Console.WriteLine("単精度浮動小数点 " + f); break; case double d: Console.WriteLine("倍精度浮動小数点 " + d); break; case string s: Console.WriteLine("文字列 " + s); break; default: Console.WriteLine("その他の型 " + obj); break; } // さらに「when句」をつけて、条件を指定することも可能 switch (obj) { case int i when i < 100: Console.WriteLine("小さな整数値 " + i); break; case int i when i > 10000: Console.WriteLine("大きな整数値 " + i); break; case int i: Console.WriteLine("普通の整数値 " + i); break; case string s when s.Length < 5: Console.WriteLine("短い文字列 " + s); break; case string s when s.Length < 10: Console.WriteLine("長い文字列 " + s); break; case string s: Console.WriteLine("普通の文字列 " + s); break; default: Console.WriteLine("その他の型 " + obj); break; } Console.WriteLine(); } public static void MultiSwitch(bool red, bool green, bool blue) { switch (red, green, blue) { case (false, false, false): Console.WriteLine("黒色"); break; case (true, true, true): Console.WriteLine("白色"); break; case (true, false, false): Console.WriteLine("赤色"); break; case (false, true, false): Console.WriteLine("緑色"); break; case (false, false, true): Console.WriteLine("青色"); break; case (true, true, false): Console.WriteLine("黄色"); break; case (true, false, true): Console.WriteLine("紫色"); break; default: Console.WriteLine("不明な色"); break; } Console.WriteLine(); } public static void Main() { // 型名で分岐させる処理を実行する TypeSwitch(new object()); TypeSwitch(1000000); TypeSwitch("test"); // 複数の値で分岐させる処理を実行する MultiSwitch(true, false, false); MultiSwitch(true, true, false); MultiSwitch(true, true, true); } } }
//実行結果
以上のように、単なる変数だけではなく、型名や複数の引数による分岐ができるので、さまざまな処理を簡潔に記述できます。ただし、switch-case文のこうした機能を使いすぎると、ソースコードの流れを追うのが難しくなることがあるため注意が必要です。
「NULL合体演算子」とは、あるオブジェクトがNULLの場合と、そうでない場合に処理を分岐できる機能です。NULL合体演算子の構文は以下のとおりです。
変数名1 = 変数名2 ?? 変数名2がnullの場合に代入する値
NULL合体演算子は、ある変数がnullでない場合とnullの場合で、変数に代入する値を分けるときによく活用されています。NULL合体演算子の使い方の例を、以下のサンプルコードに示すのでご参考ください。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { string[] test = { "a", "b", "c" }; // 通常のif-else文の場合 string find = Array.Find(test, x => x == "z"); if (find != null) { Console.WriteLine(find); } else { Console.WriteLine("該当なし"); } // 三項演算子の場合 find = Array.Find(test, x => x == "z"); Console.WriteLine(find != null ? find : "該当なし"); // NULL合体演算子の場合 Console.WriteLine(Array.Find(test, x => x == "z") ?? "該当なし"); } } }
//実行結果
上記のサンプルプログラムでは、配列の要素をFindメソッドで検索し、その戻り値がNULL・NULL以外の場合で条件分岐を行っています。Findメソッドは、要素が検出できなかったときにNULLオブジェクトが返ります。処理内容によっては、そのままアクセスするとNullReferenceExceptionが発生するため、if文・三項演算子・NULL合体演算子の3つの方法で、NULLチェックを行っていることがポイントです。
if文は非常に冗長になりますが、三項演算子はより簡潔です。NULL合体演算子を使えば、より簡潔なコーディングが可能となります。NULL合体演算子を使えば、NULLチェックと別の値の代入を同時に行えるため、必要に応じてぜひ活用しましょう。
「goto文」はこれまでの方法とは異なり、無条件でプログラムの処理の流れを変えることができます。goto文の基本的な構文は以下のとおりです。
ラベル: // ラベル内で行いたい処理 // 何らかの処理 goto ラベル;
以上の構文で、プログラムの途中で突然「ラベル」がある部分の処理へ飛ばすことができます。詳細は以下のサンプルコードのとおりですが、以下のプログラムを実行する際は、手動で「×」ボタンをクリックしないといけないので注意してください。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { // このサンプルコードを実行すると // 「×」ボタンでプログラムを強制終了する必要があるので要注意 public static void Main() { HOP: Console.WriteLine("STEPへ飛びます!"); goto STEP; JUMP: Console.WriteLine("たくさん飛びました!"); STEP: Console.WriteLine("JUMPへ飛びます!"); goto JUMP; Console.WriteLine("HOPへ飛びます!"); goto HOP; } } }
//実行結果
このようにgoto文は、ソースコードの流れが非常に追いづらくなり、多用すると思わぬバグの原因になるため、基本的には使わないようにすることが推奨されています。goto文の有効な活用法としては、先ほどご紹介したswitch-case文で、次の分岐の処理も行いたい場合です。
//サンプルプログラム
// 「System名前空間」を完全修飾名なしで使えるようにする using System; namespace Main { public class Program { public static void Main() { int i = 1; switch (i) { case 1: Console.WriteLine("ケース1"); goto case 2; // case 2ラベルに飛ぶ case 2: Console.WriteLine("ケース2"); goto default; // defaultラベルに飛ぶ case 3: Console.WriteLine("ケース3"); break; default: Console.WriteLine("デフォルト"); break; } } } }
//実行結果
switch文のcaseの正体はgotoと同じラベルなので、それを指定すれば飛ぶことが可能です。なお、C#のswitch-case文は「フォールスルー」、つまり「break」を書かずに次のcaseへ移ることが禁止されています。そこでgotoをあえて使えば、別のラベルへ移ることができるので便利です。
C#のif文・if-else文は、プログラムの処理を分岐させることができる機能で、C#でプログラミングを行う上で欠かせません。あらゆる場面で使えるうえに、条件分岐の方法も多様なため、C#のif文は非常に奥が深い機能と言えるでしょう。条件分岐では論理演算をよく使うため、それぞれの演算子の使い方を理解しておくことが重要です。
またC#には、if文以外にもswitch-case文や三項演算子など、さまざまな方法で条件分岐ができる機能が備わっています。これらの機能を活用すれば、C#であらゆる処理が書けるようになり、より複雑で高度なプログラムが作れるようになります。今回ご紹介した知識を習得して、C#の条件分岐を身に付けましょう。
2024.06.17
子供におすすめのプログラミングスクール10選!学習メリットや教室選びのコツも紹介
#プログラミングスクール
2022.01.06
【完全版】大学生におすすめのプログラミングスクール13選!選ぶコツも詳しく解説
#プログラミングスクール
2024.01.26
【未経験でも転職可】30代におすすめプログラミングスクール8選!
#プログラミングスクール
2024.01.26
初心者必見!独学のJava学習方法とおすすめ本、アプリを詳しく解説
#JAVA
2024.01.26
忙しい社会人におすすめプログラミングスクール15選!失敗しない選び方も詳しく解説
#プログラミングスクール
2022.01.06
【無料あり】大阪のおすすめプログラミングスクール14選!スクール選びのコツも紹介
#プログラミングスクール
2024.01.26
【目的別】東京のおすすめプログラミングスクール20選!スクール選びのコツも徹底解説
#プログラミングスクール
2024.01.26
【無料あり】福岡のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】名古屋のおすすめプログラミングスクール13選!選び方も詳しく解説
#プログラミングスクール
2024.01.26
【徹底比較】おすすめのプログラミングスクール18選!失敗しない選び方も徹底解説
#プログラミングスクール