普段何気なく使用している C# の機能について、 DLL をデコンパイルして実際にどのような処理がおこなわれているのかを眺めてみるコーナーです。2回目となる本記事では三項条件演算子について眺めてみたいと思います。
試した環境
要素 | バージョン |
---|---|
.NET SDK | 7.0.101 |
C# | 11.0 |
dotPeek | 2022.3.1 |
本記事ではビルド時の構成に Release を指定して出力されたアセンブリに対して、 JetBrains 社が提供している .NET デコンパイラ dotPeek を使用して検証しています。
三項条件演算子とは
三項条件演算子とは ?
と :
の2つの条件演算子を使用して、条件に対して2つの式のいずれかを評価して値を返す演算子です。
前回と同じく例を挙げる必要も無いかとは思いますが、サンプルコードだとこのようになります。
bool condition = true; int num = condition ? 1 : 0; // ←コレ
デコンパイルしてみる
それではデコンパイルをしてみましょう。コンパイルする前の元のコードはこちらです。単純な三項条件が1つだけのものと連続しているもの(同一の対象、異なる対象)とを用意しました。
public static class ConditionalOperator { /// <summary> /// 単純な三項条件式 /// </summary> public static void C1(bool condition) { var a = condition ? 1 : -1; Console.WriteLine(a); } /// <summary> /// 同一の対象に対して連続した三項条件式 /// </summary> public static void C2(int condition) { var a = condition == 1 ? 1 : condition == 2 ? 2 : 3; Console.WriteLine(a); } /// <summary> /// 異なる対象に対して連続した三項条件式 /// </summary> public static void C3(int c1, int c2) { var a = c1 == 1 ? 1 : c2 == 2 ? 2 : 3; Console.WriteLine(a); } }
これをコンパイル⇒デコンパイルするとこうなります(※コメント行は筆者が追加しています)。単純な if 文やネストされた if 文に変換されるはずと筆者は予想しているのですが、実際はどうでしょうか。
まずは単純な三項条件式の場合です。
public static void C1(bool condition) { int num; if (!condition) num = -1; else num = 1; Console.WriteLine(num); }
凄く単純な if-else に変換されました。これは予想通りです。
ILコード(クリックで表示)
IL_0000: ldarg.0 IL_0001: brtrue.s IL_0006 IL_0003: ldc.i4.m1 IL_0004: br.s IL_0007 IL_0006: ldc.i4.1 IL_0007: call void [System.Console]System.Console::WriteLine(int32) IL_000c: ret
続いて同一の対象に対して連続した三項条件式の場合です。
public static void C2(int condition) { int num; switch (condition) { case 1: num = 1; break; case 2: num = 2; break; default: num = 3; break; } Console.WriteLine(num); }
想像と違うのが出てきました。同一の対象に対して三項条件式を連続して記述すると、 switch を使った分岐と同じような状態になる様です。
ILコード(クリックで表示)
IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: beq.s IL_000e IL_0004: ldarg.0 IL_0005: ldc.i4.2 IL_0006: beq.s IL_000b IL_0008: ldc.i4.3 IL_0009: br.s IL_000f IL_000b: ldc.i4.2 IL_000c: br.s IL_000f IL_000e: ldc.i4.1 IL_000f: call void [System.Console]System.Console::WriteLine(int32) IL_0014: ret
最後に異なる対象に対して連続した三項条件式の場合です。
public static void C3(int c1, int c2) { int num; if (c1 != 1) { if (c2 != 2) num = 3; else num = 2; } else num = 1; Console.WriteLine(num); }
こちらは想像通りですね。ネストした if 文になりました。
ILコード(クリックで表示)
IL_0000: ldarg.0 IL_0001: ldc.i4.1 IL_0002: beq.s IL_000e IL_0004: ldarg.1 IL_0005: ldc.i4.2 IL_0006: beq.s IL_000b IL_0008: ldc.i4.3 IL_0009: br.s IL_000f IL_000b: ldc.i4.2 IL_000c: br.s IL_000f IL_000e: ldc.i4.1 IL_000f: call void [System.Console]System.Console::WriteLine(int32) IL_0014: ret
おわりに
2回目となる今回は三項条件演算について眺めてみました。デコンパイルされたソースコードの中身は想像通りでしたか?
普段から利用する機能であっても自身の認識と実際の挙動にズレがある場合は思わぬバグを生みかねません。この記事が少しでも C# に対する認識を深めることに役立てれば幸いです。