実はよく知らないC# 第2回:三項条件演算子

普段何気なく使用している C# の機能について、 DLL をデコンパイルして実際にどのような処理がおこなわれているのかを眺めてみるコーナーです。2回目となる本記事では三項条件演算子について眺めてみたいと思います。


試した環境

要素 バージョン
.NET SDK 7.0.101
C# 11.0
dotPeek 2022.3.1

本記事ではビルド時の構成に Release を指定して出力されたアセンブリに対して、 JetBrains 社が提供している .NET デコンパイラ dotPeek を使用して検証しています。

www.jetbrains.com

三項条件演算子とは

三項条件演算子とは ?: の2つの条件演算子を使用して、条件に対して2つの式のいずれかを評価して値を返す演算子です。

learn.microsoft.com

前回と同じく例を挙げる必要も無いかとは思いますが、サンプルコードだとこのようになります。

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# に対する認識を深めることに役立てれば幸いです。

執筆担当者プロフィール
中谷 大造

中谷 大造(日本ビジネスシステムズ株式会社)

情報システム部の中谷です。社内用スクラッチアプリの開発をしています。

担当記事一覧