読みやすさを保ちながら分岐の意図を短く書きたい時に役立つのが三項演算子(?:)です。
if-elseの代わりに1行で値を選べるため、代入や戻り値の式でとても便利です。
ただし使いどころを誤ると読みにくくなるため、シンプルな条件に限定し、型や優先順位の注意点を押さえることが大切です。
三項演算子(?:)とは
構文と読み方
三項演算子は、条件に応じて2つの値のどちらかを選ぶ演算子です。
読み方は「条件演算子」と呼ばれることもあります。
構文は次の通りです。
- 形式:
条件 ? 条件がtrueの時の値 : 条件がfalseの時の値
- 条件部分はbool型である必要があります。
基本構文の例と評価の流れ
条件がtrueなら左側、falseなら右側が評価され、その結果が式全体の値になります。
片方だけが評価されるため、余計な処理は実行されません。
// 三項演算子の評価イメージ
// condition が true なら "A"、false なら "B" を返す
string result = condition ? "A" : "B";
if-elseとの違いとメリット(1行で書ける)
if-elseは文(statement)ですが、三項演算子は式(expression)です。
つまり、代入の右辺やメソッドの戻り値などに直接書けます。
短所は、条件や分岐先が長いと一気に読みにくくなることです。
以下は特徴の早見表です。
観点 | if-else | 三項演算子(?:) |
---|---|---|
位置づけ | 文 | 式 |
主な用途 | 複数行の処理 | 値の選択を1行で |
可読性 | 複雑な分岐に強い | シンプルな分岐に強い |
副作用を伴う処理 | 書きやすい | 原則避けるべき |
三項演算子の使い方(基本例)
条件で文字列を選ぶ例
最も基本的な使い方は、数値判定からメッセージを選ぶ形です。
using System;
class Program
{
static void Main()
{
// 例1: 点数から合否メッセージを選ぶ
int score = 72;
// 条件が true のとき "合格"、false のとき "不合格"
string message = score >= 60 ? "合格" : "不合格";
Console.WriteLine($"点数:{score} → 判定:{message}");
// 例2: 時刻によって挨拶を切り替える
int hour = DateTime.Now.Hour;
string greet = hour < 12 ? "おはようございます" : "こんにちは";
Console.WriteLine($"現在時刻:{hour}時 → あいさつ:{greet}");
}
}
点数:72 → 判定:合格
現在時刻:10時 → あいさつ:おはようございます
条件で数値を選ぶ例
絶対値のように、条件で符号を反転するといった数値処理でも活躍します。
using System;
class Program
{
static void Main()
{
int x = -5;
// x が 0 以上なら x、そうでなければ -x を代入
int abs = x >= 0 ? x : -x;
// 条件によって税率を分ける例
bool isReducedTax = true;
decimal price = 1000m;
decimal taxRate = isReducedTax ? 0.08m : 0.10m;
decimal total = price * (1 + taxRate);
Console.WriteLine($"x={x}, abs={abs}");
Console.WriteLine($"軽減税率:{isReducedTax}, 税率:{taxRate}, 合計:{total}");
}
}
x=-5, abs=5
軽減税率:True, 税率:0.08, 合計:1080.00
変数への代入や戻り値の式で使う
三項演算子は式なので、初期化や戻り値で自然に使えます。
using System;
class DiscountService
{
// 会員かどうかで割引率を返すサンプル
public static decimal GetDiscount(bool isMember, int purchaseCount)
// 条件が単純なら式本体でそのまま書けます
=> isMember ? 0.15m : (purchaseCount >= 10 ? 0.05m : 0.00m);
static void Main()
{
bool isMember = false;
int purchaseCount = 12;
// 初期化時の代入
string label = isMember ? "会員" : "一般";
// 戻り値の式でも活用
decimal rate = GetDiscount(isMember, purchaseCount);
Console.WriteLine($"種別:{label}, 来店回数:{purchaseCount}, 割引率:{rate:P0}");
}
}
種別:一般, 来店回数:12, 割引率:5%
注: 上のGetDiscountは入れ子を含みますが、説明の都合上の例です。
実務では次章の方針に沿ってネストは避ける判断が望ましいです。
if-elseを?:に書き換えるコツ
シンプルな条件だけを?:にする
条件と両分岐の式が短い時にだけ使うと読みやすくなります。
比較やnullチェックのような1ステップの条件が好相性です。
書き換え例
次のようなif-elseは三項演算子に置き換えるとすっきりします。
// Before: if-else
string status;
if (age >= 20)
{
status = "成人";
}
else
{
status = "未成年";
}
// After: 三項演算子
string status2 = age >= 20 ? "成人" : "未成年";
複雑ならif-elseに戻す判断基準
以下のような場合は、読みやすさを優先してif-elseへ戻すと保守性が高まります。
- 分岐ごとに複数行の処理が必要な時
- ログ出力や状態変更など副作用を伴う時
- 条件式が長く、かっこだらけで判読が難しい時
- ネスト(入れ子)や三者以上の分岐を無理に1行で表そうとしている時
ネスト(?:の入れ子)は避ける
三つ以上の選択肢を無理に1行で書くと可読性が大きく落ちます。
// 悪い例: ネストで分岐が読みにくい
string level = score >= 80 ? "A"
: score >= 65 ? "B"
: score >= 50 ? "C"
: "D";
代わりに、素直にif-elseへ戻すと意図が明確です。
// 良い例: 素直なif-elseに戻す
string level;
if (score >= 80) level = "A";
else if (score >= 65) level = "B";
else if (score >= 50) level = "C";
else level = "D";
「1行で書ける」ことより「次の人がすぐ読める」ことを優先しましょう。
三項演算子の注意点(C#初心者向け)
型をそろえる(型推論のポイント)
三項演算子の第2項と第3項は、同じ型か、共通の型へ暗黙変換できる型である必要があります。
合わない時は明示的キャストを検討します。
using System;
class Program
{
static void Main()
{
bool flag = true;
// OK: 両方とも int
int a = flag ? 1 : 0;
// OK: int と double は double に統一される
double b = flag ? 1 : 0.5; // 1 は 1.0 に暗黙変換
// NG例: string と int は共通型にできない
// var c = flag ? "one" : 1; // コンパイルエラー
// 対策: 片方を明示的に変換して型をそろえる
string c = flag ? "1" : 1.ToString();
Console.WriteLine($"{a}, {b}, {c}");
}
}
1, 1, 1
補足: null
を含む場合、参照型同士やNullable<T>
との組み合わせなら共通型に収束できます。
統一できない時は(T)null
のように型を明示します。
優先順位が低いのでかっこで明確にする
三項演算子は演算子の優先順位が低めです。
意図が曖昧に読める箇所はかっこで括ると安全です。
// 意図を明確にするためにかっこを使う
int x = 3, y = -1;
int result = (x + y >= 0) ? (x + y) : 0; // 合計が負なら0
副作用のある処理は入れない
三項演算子は「値を選ぶ」ための道具です。
ログ出力やフィールド更新などの副作用を混ぜると読みづらく、デバッグも難しくなります。
// 悪い例: 分岐内で副作用を起こす
string label = isValid ? LogAnd("OK") : LogAnd("NG"); // ログも兼ねる関数を呼ぶ…読みにくい
// 良い例: 値の選択は三項演算子、ログは別に
string label2 = isValid ? "OK" : "NG";
Console.WriteLine($"判定:{label2}");
可読性を最優先にする
- 短く正確に読めるかを常に確認します。条件・両分岐・結果の型が視認しやすいことが理想です。
- 名前づけや補助変数で意味を明確にすると、三項演算子でも読みやすくなります。
- 迷ったらif-elseへ戻す判断を優先しましょう。
まとめ
三項演算子(?:)は、「条件に応じて値を選ぶ」処理を1行で表せる強力な表現です。
C#では式として代入や戻り値で自然に使え、簡単な分岐の可読性を高められます。
一方で、条件や分岐が長い・副作用を含む・ネストが必要といった場面ではif-elseに戻すのが得策です。
型の整合性と演算子優先順位に注意し、シンプルな条件に限定して活用すれば、コードは簡潔で意図の明確なものになります。