メインコンテンツまでスキップ

第15章:Result型の考え方(成功/失敗の箱)🎁✅❌

0. この章のゴール🎯✨

この章が終わったら、こんな判断ができるようになるよ〜😊💡

  • 「これは想定内の失敗だから Result で返そう🎁」
  • 「これは**想定外(バグ/不変条件違反)**だから例外で落としてOK⚡」
  • 呼び出し側が読みやすい“失敗の扱い方”が分かる🔀✨
  • TryParse みたいな「失敗しても普通」パターンが Result 的だと腹落ちする🧩

1. Result型ってなに?(超ざっくり)🎁

Result Box

Result型は、関数の返り値を

  • ✅ 成功:値が入ってる
  • ❌ 失敗:エラー情報が入ってる

…という 「箱」 にする考え方だよ📦✨ 例外みたいに「投げて上に飛ばす」じゃなくて、**“戻り値として、失敗もちゃんと返す”**のがポイント🙂


2. なんで Result が欲しくなるの?(例外だけだと困る場面)😵‍💫💥

2-1. 例外は “よく起きる失敗” に使うとしんどい🙅‍♀️

Microsoft の例外ベストプラクティスでも、起きがちな条件は例外を避けて if で扱うのが推奨されてるよ🧯 (例:接続が閉じてるなら Close しない、みたいな) (Microsoft Learn)

つまり、「入力ミス」みたいに日常的に起きる失敗を毎回例外でやると、

  • 制御が飛ぶ🌀(読みづらい)
  • エラーパスが見えにくい👀
  • 例外にはスタックトレース等の情報が付く(=重い情報を運ぶ仕組み)🧵 (Microsoft Learn)

…みたいな理由で、つらくなりがち💦


3) 「例外」VS「Result」ざっくり使い分け早見表🚦✨

状況どう扱う?理由
ユーザーの入力ミス(必ず起きうる)✍️Result ✅想定内の失敗=仕様として返したい
業務ルール違反(在庫なし、予算超え)🧾Result ✅ドメインエラーとして丁寧に扱う
DB/外部APIが落ちた🌩️だいたい Result ✅(境界で変換)上に「再試行できる?」などを渡したい
Null 参照、前提が崩れた、不変条件違反💥例外 ⚡想定外=バグ。早く気づく(Fail Fast)

※この「想定内/外」の線引きが、第5章〜第9章でやった“分類”の出番だよ🧩💗🌩️⚡


4. Result 的な考え方、もう .NET にあるよ!(TryParse がそれ)🧠✨

たとえば TryParse

  • 変換できた? → true
  • できなかった? → false
  • できた場合の値は out で返す

っていう「失敗しても普通」設計だよね🙂 実際 Boolean.TryParse も「成功したら true、失敗したら false」を返すって明記されてるよ✅❌ (Microsoft Learn)

つまり TryParse = Result の親戚👨‍👩‍👧‍👦✨ Result はこれをもっと一般化して、

  • 成功なら値
  • 失敗ならエラー情報(コードやメッセージ)

まで持てるようにした感じだよ🎁🧾


5. 例外版 → Result版 にすると何が嬉しい?🎀✨

5-1. 呼び出し側が「読んだだけで分かる」📖👀

例外だと「どこで飛ぶか」がコード上ぱっと見えにくいけど、Result だと

  • 成功 → 次へ
  • 失敗 → ここで返す/表示する

制御フローとして見えるのが強い💪✨


6. 実例:入力チェックを「例外 → Result」へ🔁✨

6-1. まず悪くないけど、例外でやると“日常失敗”に弱い版😅

(例:予算は 0 以上じゃないとダメ、みたいな想定内ルール)

public static int ParseBudgetOrThrow(string text)
{
// ユーザーは普通に間違えるので、ここで例外を投げる設計はつらくなりがち💦
return int.Parse(text); // 失敗すると例外
}

6-2. TryParse を挟むだけでも Result 的になる🙂✨

public static bool TryParseBudget(string text, out int budget)
{
return int.TryParse(text, out budget);
}

6-3. Result にすると「失敗理由」まで運べる🎁🧾

※Result本体の“完成版”は次章(第16章)で作るから、ここは最小の雰囲気だけね😊

public abstract record AppError(string Code, string Message);

public sealed record ValidationError(string Code, string Message)
: AppError(Code, Message);

public readonly record struct Result<T>(bool IsSuccess, T? Value, AppError? Error)
{
public static Result<T> Ok(T value) => new(true, value, null);
public static Result<T> Fail(AppError error) => new(false, default, error);
}

public static Result<int> ParseBudget(string text)
{
if (!int.TryParse(text, out var budget))
return Result<int>.Fail(new ValidationError("BUDGET_NOT_NUMBER", "予算は数字で入れてね🥺"));

if (budget < 0)
return Result<int>.Fail(new ValidationError("BUDGET_NEGATIVE", "予算は0以上にしてね🙏"));

return Result<int>.Ok(budget);
}

呼び出し側はこうなるよ👇✨

var result = ParseBudget(input);

if (!result.IsSuccess)
{
Console.WriteLine(result.Error!.Message);
return;
}

Console.WriteLine($"予算OK: {result.Value} 円🎉");

**「失敗したらここで終わり」**が自然に書けるのが Result の気持ちよさだよ〜🛑✨


7. ミニ演習(手を動かそ〜!)🧪💪✨

演習1:例外を Result に置き換え🔁

次の関数を「例外を投げない」で Result で返すようにしてみてね🙂

  • 変換できない → VALIDATION_NOT_NUMBER
  • 0以下 → VALIDATION_OUT_OF_RANGE

(ヒント:TryParse + if)


演習2:「例外?Result?」仕分けクイズ🎯

次をどっちで扱う?理由も1行で✨

  1. メールアドレス形式が変📧
  2. DB 接続タイムアウト⏳
  3. 在庫が足りない📦
  4. null が来た(絶対来ない想定)💥
  5. 外部APIが 503 を返した🌩️

8. AI活用(Copilot / Codex)🤖✨:この章の使い方

AIは“答えを決める係”じゃなくて、判断材料を増やす係にすると強いよ💪😊

8-1. そのまま使えるプロンプト集📮✨

  • 「この失敗は “想定内” ですか? “想定外” ですか?理由も3つで」
  • 「このコードを Result 返しにリファクタして。エラーコード案も出して」
  • 「Result にすべきケース/例外にすべきケースを、この関数の仕様から整理して」
  • 「呼び出し側が読みやすい early return 形に直して」

9. ちょい最新メモ(2026視点)🗓️✨

C# 14 は .NET 10 上でサポートされてて、Visual Studio 2026 に .NET 10 SDK が含まれるよ🪟🛠️ (Microsoft Learn) それと .NET 10 は 2025-11-11 に開始(LTS)って Lifecycle に載ってるよ📌 (Microsoft Learn)


まとめ🎀✨

  • Result は「成功/失敗を返り値に入れる箱」🎁
  • 想定内の失敗=Result想定外(バグ)=例外 が基本🚦
  • TryParse は Result 的発想の超身近な例🧩 (Microsoft Learn)
  • “起きがちな条件は例外を避ける”のが .NET の推奨にも沿うよ🧯 (Microsoft Learn)

次の第16章では、この Result を「ちゃんとした形」で組み立てて、テストも少し書いて“道具として使える”ところまで作っちゃお〜😊🧰🧪✨