C#のNotImplementedExceptionとは?発生原因・使い方・解決方法を初心者向けに徹底解説
はじめに
C#でアプリケーションを開発していると、実行時にSystem.NotImplementedExceptionという例外が発生することがあります。特に、Visual Studioでインターフェースや抽象クラスを実装した直後、またはサンプルコードをそのまま実行したときに見かけやすい例外です。
NotImplementedExceptionは、名前のとおり「まだ実装されていない処理が呼び出された」ことを表す例外です。初心者のうちは、コンパイルは成功しているのに実行するとエラーになるため、原因がわかりにくいと感じるかもしれません。
この記事では、C#のNotImplementedExceptionの意味、発生原因、基本的な使い方、具体的なコード例、解決方法、よく似た例外との違いまで、初心者にもわかりやすく解説します。
1. C#のNotImplementedExceptionとは?
1-1. NotImplementedExceptionの意味を初心者向けに解説
NotImplementedExceptionとは、C#で「この処理はまだ実装されていません」と明示するために使われる例外です。
たとえば、次のようなコードがあります。
C#public void Save()
{
throw new NotImplementedException();
}
このSaveメソッドは定義されていますが、中身の処理はまだ書かれていません。そのため、このメソッドが実行されるとNotImplementedExceptionが発生します。
重要なのは、NotImplementedExceptionは「C#の文法ミス」ではないということです。コードとしては正しいためコンパイルは通ります。しかし、実行時にその行へ到達すると例外が投げられます。
1-2. .NETで用意されている例外クラスとしての位置づけ
NotImplementedExceptionは、.NETに標準で用意されている例外クラスです。名前空間はSystemです。
C#System.NotImplementedException
C#では、エラーや異常な状態を表すために例外クラスを使用します。NotImplementedExceptionもその一種で、Exceptionクラスを継承しています。
一般的な例外には、次のようなものがあります。
C#ArgumentException
InvalidOperationException
NotSupportedException
NotImplementedException
この中でNotImplementedExceptionは、主に開発途中のコードや未完成の機能を表すために使われます。
1-3. 「まだ実装されていない処理」を示すための例外
NotImplementedExceptionの役割は、「このメソッドやプロパティは存在するが、処理内容はまだ作っていない」と示すことです。
たとえば、将来的に実装する予定のメソッドだけを先に用意しておきたい場合があります。
C#public int CalculateTotalPrice()
{
throw new NotImplementedException();
}
このように書いておくと、メソッドを呼び出した時点で未実装であることが明確になります。
単に空のメソッドにしてしまうと、処理が何も行われず、バグに気づきにくくなります。一方でNotImplementedExceptionを投げておけば、実行時にすぐ問題がわかります。
1-4. NotSupportedExceptionやNotFiniteNumberExceptionとの違い
NotImplementedExceptionと混同されやすい例外に、NotSupportedExceptionがあります。
NotImplementedExceptionは「まだ実装していない」場合に使います。一方、NotSupportedExceptionは「仕様としてサポートしない」場合に使います。
たとえば、将来的に保存機能を作る予定があるならNotImplementedExceptionが適しています。
C#public void Save()
{
throw new NotImplementedException();
}
一方で、読み取り専用のオブジェクトに保存処理を用意しない設計であれば、NotSupportedExceptionが適しています。
C#public void Save()
{
throw new NotSupportedException("このオブジェクトは保存をサポートしていません。");
}
また、NotFiniteNumberExceptionは数値計算で無限大や非数を扱う場合に関連する例外です。NotImplementedExceptionとは用途がまったく異なります。
2. NotImplementedExceptionが発生する主な原因
2-1. Visual Studioの自動生成コードに残っている
NotImplementedExceptionが発生する原因として特に多いのが、Visual Studioの自動生成コードに残っているケースです。
Visual Studioでは、インターフェースを実装すると、必要なメソッドやプロパティを自動生成できます。そのとき、メソッドの中身として次のようなコードが自動で入ることがあります。
C#throw new NotImplementedException();
これは「メソッドの形だけは作ったので、中身は開発者があとで実装してください」という意味です。
自動生成されたからといって、処理まで完成しているわけではありません。初心者が見落としやすいポイントです。
2-2. インターフェースや抽象クラスの実装が未完成
C#では、インターフェースや抽象クラスを使うと、指定されたメンバーを実装する必要があります。
たとえば、次のようなインターフェースがあるとします。
C#public interface IRepository
{
void Save();
}
このインターフェースを実装するクラスでは、Saveメソッドを用意する必要があります。
C#public class UserRepository : IRepository
{
public void Save()
{
throw new NotImplementedException();
}
}
この状態では、Saveメソッドの形はありますが、実際の保存処理はまだ書かれていません。そのため、実行するとNotImplementedExceptionが発生します。
2-3. TODO代わりにthrow new NotImplementedException()を書いている
開発中に「あとで実装する」という意味で、TODOコメントの代わりにNotImplementedExceptionを書くことがあります。
C#public void SendMail()
{
// TODO: メール送信処理を実装する
throw new NotImplementedException();
}
この書き方自体は開発途中では便利です。しかし、実装を忘れたままリリースしてしまうと、ユーザーがその機能を使ったときにアプリケーションエラーになります。
NotImplementedExceptionは、未実装箇所を明確にするためのものです。TODO代わりに使う場合でも、最終的には必ず本実装に置き換える必要があります。
2-4. サンプルコードやテンプレートをそのまま実行している
書籍、ブログ、公式ドキュメント、チュートリアルなどのサンプルコードには、説明を簡略化するためにNotImplementedExceptionが含まれていることがあります。
C#public string GetUserName(int userId)
{
throw new NotImplementedException();
}
これは「ここにユーザー名を取得する処理を書いてください」という意味であり、そのまま実行できる完成コードではありません。
テンプレートコードやサンプルコードを使う場合は、throw new NotImplementedException()が残っていないか確認しましょう。
2-5. ライブラリやフレームワーク側で未実装の処理を呼び出している
まれに、自分が直接書いたコードではなく、利用しているライブラリやフレームワーク側でNotImplementedExceptionが発生することもあります。
たとえば、特定の環境では対応していない機能、まだ完成していないAPI、プレビュー版のライブラリなどを呼び出した場合です。
この場合は、自分のコードだけでなく、スタックトレースを確認して、どのライブラリのどのメソッドで例外が発生しているかを調べる必要があります。
3. NotImplementedExceptionの基本的な使い方
3-1. throw new NotImplementedException()の書き方
NotImplementedExceptionの基本的な書き方は次のとおりです。
C#throw new NotImplementedException();
メソッドの中で使用する場合は、次のようになります。
C#public void Print()
{
throw new NotImplementedException();
}
このPrintメソッドを呼び出すと、NotImplementedExceptionが発生します。
C#Print();
NotImplementedExceptionは、あくまで「未実装」を示すための例外です。通常の業務ロジックで頻繁に使うものではありません。
3-2. メソッド・プロパティ・イベントで使う例
NotImplementedExceptionは、メソッドだけでなく、プロパティやイベントでも使われることがあります。
メソッドで使う例です。
C#public void Execute()
{
throw new NotImplementedException();
}
プロパティのgetで使う例です。
C#public string Name
{
get
{
throw new NotImplementedException();
}
}
プロパティのsetで使う例です。
C#public string Name
{
set
{
throw new NotImplementedException();
}
}
イベントで使う例です。
C#public event EventHandler Completed
{
add
{
throw new NotImplementedException();
}
remove
{
throw new NotImplementedException();
}
}
ただし、実際の開発ではプロパティやイベントにNotImplementedExceptionが残っていると、原因がわかりにくい不具合になることがあります。使う場合は、必ず未実装であることを管理しましょう。
3-3. インターフェース実装時に自動生成されるコード例
次のようなインターフェースがあるとします。
C#public interface IUserService
{
string GetUserName(int id);
}
Visual Studioなどで自動実装すると、次のようなコードが生成されることがあります。
C#public class UserService : IUserService
{
public string GetUserName(int id)
{
throw new NotImplementedException();
}
}
このコードは、インターフェースの実装としては形が整っています。しかし、実際の処理は未完成です。
正しく実装するなら、たとえば次のように処理を書きます。
C#public class UserService : IUserService
{
public string GetUserName(int id)
{
return "山田太郎";
}
}
もちろん実際のアプリケーションでは、データベースやAPIからユーザー情報を取得する処理を書くことが多いです。
3-4. メッセージ付きで例外を投げる方法
NotImplementedExceptionには、メッセージを付けて投げることもできます。
C#throw new NotImplementedException("ユーザー検索機能はまだ実装されていません。");
メッセージを付けると、エラー内容がわかりやすくなります。
C#public void SearchUser()
{
throw new NotImplementedException("SearchUserメソッドは現在開発中です。");
}
開発中のチームでは、どの機能が未実装なのかをメッセージに書いておくと、デバッグやレビューのときに役立ちます。
3-5. スタックトレースで発生箇所を確認する方法
NotImplementedExceptionが発生したら、スタックトレースを確認することが大切です。
スタックトレースとは、例外が発生するまでに呼び出されたメソッドの履歴です。
たとえば、次のようなエラーが表示されることがあります。
System.NotImplementedException: The method or operation is not implemented.
at SampleApp.UserService.GetUserName(Int32 id)
at SampleApp.Program.Main(String[] args)
この場合、UserService.GetUserNameメソッドでNotImplementedExceptionが発生し、それをProgram.Mainから呼び出していることがわかります。
初心者のうちは、エラーメッセージだけを見るのではなく、「どのファイルのどの行で発生しているか」を確認する習慣をつけましょう。
4. NotImplementedExceptionの具体的なコード例
4-1. メソッドが未実装の場合のサンプル
次のコードでは、Calculateメソッドが未実装です。
C#using System;
public class Calculator
{
public int Calculate(int x, int y)
{
throw new NotImplementedException();
}
}
public class Program
{
public static void Main()
{
var calculator = new Calculator();
int result = calculator.Calculate(10, 20);
Console.WriteLine(result);
}
}
このコードを実行すると、Calculateメソッド内でNotImplementedExceptionが発生します。
解決するには、必要な処理を実装します。
C#public int Calculate(int x, int y)
{
return x + y;
}
このようにすれば、Calculate(10, 20)の結果として30が返されます。
4-2. インターフェース実装時のサンプル
インターフェースを実装するときにもNotImplementedExceptionがよく登場します。
C#using System;
public interface IMessageSender
{
void Send(string message);
}
public class EmailSender : IMessageSender
{
public void Send(string message)
{
throw new NotImplementedException();
}
}
この状態でSendメソッドを呼び出すと、例外が発生します。
C#IMessageSender sender = new EmailSender();
sender.Send("こんにちは");
解決するには、メール送信処理や仮の出力処理を実装します。
C#public class EmailSender : IMessageSender
{
public void Send(string message)
{
Console.WriteLine($"メールを送信しました: {message}");
}
}
このように、インターフェースのメソッドは形だけでなく中身まで実装する必要があります。
4-3. 抽象クラスを継承した場合のサンプル
抽象クラスを継承した場合にも、未実装のメソッドでNotImplementedExceptionを使うことがあります。
C#using System;
public abstract class Report
{
public abstract void Export();
}
public class PdfReport : Report
{
public override void Export()
{
throw new NotImplementedException();
}
}
PdfReportクラスではExportメソッドをオーバーライドしていますが、処理内容は未実装です。
実装する場合は、次のように書き換えます。
C#public class PdfReport : Report
{
public override void Export()
{
Console.WriteLine("PDFレポートを出力しました。");
}
}
抽象クラスを継承すると、抽象メンバーを必ず実装する必要があります。ただし、自動生成されたメソッドにNotImplementedExceptionが残っている場合は、実装完了とはいえません。
4-4. プロパティのget/setで発生するサンプル
プロパティのgetやsetにNotImplementedExceptionが残っていると、値を取得または設定したタイミングで例外が発生します。
C#using System;
public class User
{
public string Name
{
get
{
throw new NotImplementedException();
}
set
{
throw new NotImplementedException();
}
}
}
このコードでは、次のどちらでも例外が発生します。
C#var user = new User();
user.Name = "佐藤";
Console.WriteLine(user.Name);
正しく実装するには、フィールドや自動実装プロパティを使います。
C#public class User
{
public string Name { get; set; }
}
または、明示的にフィールドを用意します。
C#public class User
{
private string name;
public string Name
{
get
{
return name;
}
set
{
name = value;
}
}
}
4-5. 実行時エラーとして表示される例
NotImplementedExceptionはコンパイル時ではなく、実行時に発生します。
たとえば、次のコードはコンパイルできます。
C#public void Run()
{
throw new NotImplementedException();
}
しかし、実際にRunメソッドを呼び出すと、次のような実行時エラーになります。
System.NotImplementedException: The method or operation is not implemented.
つまり、NotImplementedExceptionが書かれているだけではエラーにならず、その処理が実行されたときに初めて問題になります。
そのため、アプリケーション内にNotImplementedExceptionが残っていても、テストでその機能を通らなければ気づけないことがあります。
5. NotImplementedExceptionの解決方法
5-1. 例外が発生している場所を特定する
NotImplementedExceptionを解決する第一歩は、どこで発生しているかを特定することです。
Visual Studioでデバッグ実行している場合、例外が発生した行で停止することがあります。その行に次のようなコードがあれば、そこが原因です。
C#throw new NotImplementedException();
また、エラーメッセージやスタックトレースにも発生箇所が表示されます。
at SampleApp.UserService.GetUserName(Int32 id)
この情報をもとに、対象のクラスやメソッドを確認しましょう。
5-2. 未実装のメソッドに必要な処理を追加する
NotImplementedExceptionの基本的な解決方法は、未実装の処理を実装することです。
たとえば、次のようなメソッドがあるとします。
C#public int Add(int a, int b)
{
throw new NotImplementedException();
}
加算処理を実装するなら、次のように書き換えます。
C#public int Add(int a, int b)
{
return a + b;
}
データ取得、保存、計算、画面表示など、メソッドの目的に合わせて正しい処理を追加します。
5-3. 不要なthrow文を削除する
処理を実装したあとに、throw new NotImplementedException()を残してしまうと、メソッドは途中で例外を投げてしまいます。
悪い例です。
C#public int Add(int a, int b)
{
int result = a + b;
throw new NotImplementedException();
return result;
}
このようなコードは正しく動作しません。不要なthrow文は削除しましょう。
正しい例です。
C#public int Add(int a, int b)
{
int result = a + b;
return result;
}
また、throw文より後ろにあるコードは実行されないため、到達不能コードになる場合もあります。
5-4. インターフェースや抽象メンバーを正しく実装する
インターフェースや抽象クラスを使っている場合は、メンバーの意味を理解して正しく実装する必要があります。
たとえば、次のようなインターフェースがあります。
C#public interface IUserRepository
{
User FindById(int id);
}
自動生成されたままだと、次のようになっているかもしれません。
C#public User FindById(int id)
{
throw new NotImplementedException();
}
これを、実際の処理に置き換えます。
C#public User FindById(int id)
{
return users.FirstOrDefault(user => user.Id == id);
}
重要なのは、「とりあえず例外を消す」のではなく、「そのメソッドが本来何をすべきか」を考えて実装することです。
5-5. 仮実装から本実装へ置き換える
開発途中では、仮実装としてNotImplementedExceptionを使うことがあります。しかし、機能を完成させる段階では本実装へ置き換える必要があります。
仮実装の例です。
C#public string GetStatus()
{
throw new NotImplementedException();
}
一時的な戻り値を返す仮実装にすることもできます。
C#public string GetStatus()
{
return "未処理";
}
最終的には、実際の状態に応じた処理を実装します。
C#public string GetStatus()
{
return isCompleted ? "完了" : "未処理";
}
仮実装は便利ですが、リリース前には必ず見直しましょう。
5-6. デバッグ時に確認すべきポイント
NotImplementedExceptionが出たときは、次の点を確認すると原因を見つけやすくなります。
まず、例外が発生した行にthrow new NotImplementedException()があるか確認します。次に、そのメソッドがどこから呼び出されているかをスタックトレースや呼び出し履歴で確認します。
また、そのコードが自分で書いたものなのか、自動生成されたものなのか、外部ライブラリのものなのかも重要です。
自分のコードであれば、必要な処理を実装します。外部ライブラリであれば、バージョン、対応環境、使い方、既知の不具合などを確認しましょう。
6. NotImplementedExceptionを使うべき場面・使わない方がよい場面
6-1. 開発途中の仮実装として使う場合
NotImplementedExceptionは、開発途中の仮実装として使うと便利です。
たとえば、クラス設計を先に進めたいが、細かい処理はあとで書きたい場合に使えます。
C#public void ExportCsv()
{
throw new NotImplementedException("CSV出力機能は未実装です。");
}
このようにしておくと、未実装のメソッドを誤って呼び出したときにすぐ気づけます。
空のメソッドにしてしまうと、何も起こらず正常に動いているように見えることがあります。未実装であることを明確にしたい場合は、NotImplementedExceptionが役立ちます。
6-2. チーム開発で未実装箇所を明示する場合
チーム開発では、複数人が同じプロジェクトに関わります。そのため、どの機能が未実装なのかを明確にしておくことが重要です。
NotImplementedExceptionを使うと、「この処理はまだ作られていない」ということがコード上で明確になります。
C#public void ImportData()
{
throw new NotImplementedException("担当者Aが実装予定の処理です。");
}
ただし、担当者名や予定を書く場合は、コメントやIssue管理ツールとあわせて使うとよいでしょう。コード内だけで管理すると、見落とされる可能性があります。
6-3. 本番環境のコードに残すべきではない理由
NotImplementedExceptionは、本番環境のコードに残すべきではありません。
理由は、ユーザーがその処理を実行した瞬間にアプリケーションエラーになるからです。
たとえば、購入処理、保存処理、ログイン処理などにNotImplementedExceptionが残っていると、重大な障害につながります。
開発中は便利ですが、本番リリース前には必ず検索して確認しましょう。
NotImplementedException
throw new NotImplementedException
これらの文字列でプロジェクト全体を検索すると、残っている未実装コードを見つけやすくなります。
6-4. 仕様上サポートしない処理にはNotSupportedExceptionを使う
NotImplementedExceptionは「まだ実装していない」場合に使います。
一方で、「今後も実装する予定がなく、仕様として対応しない」場合はNotSupportedExceptionを使います。
たとえば、読み取り専用のコレクションで追加処理を禁止する場合です。
C#public void Add(string item)
{
throw new NotSupportedException("このコレクションには項目を追加できません。");
}
これは未実装ではなく、仕様としてサポートしていない処理です。そのためNotSupportedExceptionが適切です。
6-5. TODOコメントとの使い分け
TODOコメントとNotImplementedExceptionは似ていますが、役割が違います。
TODOコメントは、開発者に対するメモです。
C#// TODO: 入力チェックを追加する
一方、NotImplementedExceptionは、実行時に例外を発生させます。
C#throw new NotImplementedException();
まだ呼び出されてはいけない未実装メソッドにはNotImplementedExceptionが適しています。既に動作している処理に改善予定を残すだけなら、TODOコメントの方が適しています。
7. NotImplementedExceptionとよく混同される例外
7-1. NotSupportedExceptionとの違い
NotImplementedExceptionとNotSupportedExceptionは、特に混同されやすい例外です。
NotImplementedExceptionは「まだ実装していない」ことを表します。
C#public void Export()
{
throw new NotImplementedException();
}
NotSupportedExceptionは「仕様としてサポートしていない」ことを表します。
C#public void Export()
{
throw new NotSupportedException("この形式での出力はサポートしていません。");
}
将来的に実装する予定があるならNotImplementedException、今後も対応しない設計ならNotSupportedExceptionを選ぶとよいでしょう。
7-2. InvalidOperationExceptionとの違い
InvalidOperationExceptionは、「オブジェクトの現在の状態ではその操作を実行できない」場合に使います。
たとえば、接続が開かれていない状態でデータを送信しようとした場合です。
C#public void Send()
{
if (!isConnected)
{
throw new InvalidOperationException("接続されていないため送信できません。");
}
// 送信処理
}
これは未実装ではありません。条件が整っていないため、今は操作できないという意味です。
NotImplementedExceptionは処理そのものが未完成の場合に使います。
7-3. PlatformNotSupportedExceptionとの違い
PlatformNotSupportedExceptionは、特定のプラットフォームでは機能がサポートされていない場合に使います。
たとえば、Windowsでは使えるがLinuxでは使えない機能、または特定のOSや環境では対応していないAPIなどです。
C#throw new PlatformNotSupportedException("この機能は現在のプラットフォームでは使用できません。");
NotImplementedExceptionは実装が未完成であることを示しますが、PlatformNotSupportedExceptionは環境やプラットフォームの制約を示します。
7-4. ArgumentException系の例外との違い
ArgumentException系の例外は、メソッドに渡された引数が不正な場合に使います。
たとえば、名前が空文字だった場合です。
C#public void SetName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
throw new ArgumentException("名前を入力してください。", nameof(name));
}
this.name = name;
}
これはメソッド自体は実装済みですが、渡された値に問題があるケースです。
NotImplementedExceptionは、引数の値に関係なく、処理自体がまだ作られていない場合に使います。
7-5. どの例外を選ぶべきかの判断基準
どの例外を選ぶか迷った場合は、原因を基準に考えると判断しやすくなります。
処理がまだ作られていないならNotImplementedExceptionです。仕様として対応しないならNotSupportedExceptionです。現在の状態では実行できないならInvalidOperationExceptionです。特定の環境で使えないならPlatformNotSupportedExceptionです。渡された引数が不正ならArgumentException系を使います。
例外は、発生した問題の意味を正しく伝えるために選ぶものです。何でもNotImplementedExceptionにするのではなく、状況に合った例外を使いましょう。
8. Visual StudioでNotImplementedExceptionが出たときの対処法
8-1. エラーメッセージの読み方
Visual StudioでNotImplementedExceptionが発生すると、例外メッセージが表示されます。
よくあるメッセージは次のようなものです。
System.NotImplementedException: 'The method or operation is not implemented.'
これは「メソッドまたは操作が実装されていません」という意味です。
このメッセージが出た場合は、まずthrow new NotImplementedException()がどこに書かれているかを確認します。
8-2. 例外が発生した行へジャンプする方法
Visual Studioでデバッグ実行中に例外が発生すると、通常は例外が発生した行が強調表示されます。
その行に次のようなコードがあれば、そこが直接の原因です。
C#throw new NotImplementedException();
もし自動で該当行に移動しない場合は、エラー画面や出力ウィンドウ、例外の詳細に表示されているファイル名や行番号を確認します。
初心者はエラーメッセージ全体に圧倒されがちですが、まず見るべきなのは「例外の種類」と「発生した場所」です。
8-3. 呼び出し履歴から原因を追跡する方法
NotImplementedExceptionが発生した場所がわかっても、「なぜそのメソッドが呼ばれたのか」がわからない場合があります。
その場合は、呼び出し履歴を確認します。
呼び出し履歴を見ると、どのメソッドから順番に呼ばれて、最終的にNotImplementedExceptionが発生したのかがわかります。
たとえば、次のような流れです。
Program.Main
→ UserController.Create
→ UserService.Save
→ UserRepository.Insert
この場合、直接例外を投げているのはUserRepository.Insertかもしれませんが、最初のきっかけはProgram.MainやUserController.Createにあります。
呼び出し元を確認することで、意図しないタイミングで未実装メソッドが呼ばれていないかを調べられます。
8-4. 自動生成されたthrow文を見つける方法
プロジェクト内にNotImplementedExceptionが残っていないか確認するには、Visual Studioの検索機能を使います。
検索対象として、次の文字列を指定します。
throw new NotImplementedException
または、より広く検索するなら次の文字列でもよいです。
NotImplementedException
検索結果に表示された箇所を一つずつ確認し、本当に未実装でよいのか、本実装に置き換えるべきなのかを判断します。
特にリリース前には、プロジェクト全体で検索して確認することをおすすめします。
8-5. デバッグ実行で確認する手順
NotImplementedExceptionの原因を調べる基本的な手順は次のとおりです。
まず、Visual Studioでデバッグ実行します。次に、例外が発生したら停止した行を確認します。その行にthrow new NotImplementedException()があるか確認します。
次に、呼び出し履歴を見て、そのメソッドがどこから呼ばれたのかを調べます。そして、そのメソッドに本来必要な処理を実装するか、呼び出し自体が不要であれば呼び出し元を修正します。
最後に、再度デバッグ実行して、例外が発生しないことを確認します。
9. 初心者が注意すべきNotImplementedExceptionの落とし穴
9-1. コンパイルエラーではなく実行時エラーである
NotImplementedExceptionで初心者が混乱しやすい理由は、コンパイルエラーではなく実行時エラーだからです。
次のコードはコンパイルできます。
C#public void Test()
{
throw new NotImplementedException();
}
しかし、Testメソッドを呼び出すと実行時にエラーになります。
つまり、「ビルドが成功したからすべての処理が完成している」とは限りません。コンパイルは文法や型のチェックを行いますが、処理の中身が完成しているかまでは判断してくれません。
9-2. 自動生成されたコードを実装済みと勘違いしない
Visual Studioでインターフェースを自動実装すると、メソッドやプロパティの形が作られます。
しかし、そこにNotImplementedExceptionが入っている場合、その処理は未完成です。
C#public void Save()
{
throw new NotImplementedException();
}
見た目上はメソッドが存在しているため、実装済みだと勘違いしやすいです。
自動生成は、あくまで「実装のひな形を作る機能」です。中身のロジックは開発者が書く必要があります。
9-3. とりあえず削除すると別の不具合につながる
NotImplementedExceptionが出たからといって、単純にthrow文を削除すればよいわけではありません。
悪い例です。
C#public int GetPrice()
{
}
戻り値が必要なメソッドでは、何かしらの値を返さなければコンパイルエラーになります。
仮に戻り値のないメソッドでthrow文だけを削除した場合も、何も処理しないメソッドになってしまいます。
C#public void Save()
{
}
これでは保存処理が実行されず、データが失われる可能性があります。
削除するのではなく、そのメソッドに必要な処理を正しく実装しましょう。
9-4. 例外処理で握りつぶしてはいけない理由
NotImplementedExceptionをtry-catchで捕まえて無視するのは、根本的な解決になりません。
悪い例です。
C#try
{
service.Save();
}
catch (NotImplementedException)
{
// 何もしない
}
このようにすると、エラーは表面上見えなくなります。しかし、保存処理が実行されていないという問題は残ったままです。
例外を握りつぶすと、後から原因を追跡しにくくなります。NotImplementedExceptionが発生した場合は、基本的に未実装の処理を実装することが正しい解決方法です。
9-5. 本番リリース前に残っていないか確認する
本番リリース前には、NotImplementedExceptionが残っていないか必ず確認しましょう。
確認方法としては、プロジェクト全体検索が有効です。
NotImplementedException
また、単体テストや結合テストで主要な機能を実行し、未実装のメソッドが呼び出されないか確認します。
特に、普段あまり使われない画面、エラー時だけ通る処理、管理者向け機能などに未実装コードが残りやすいため注意が必要です。
10. NotImplementedExceptionを防ぐための開発習慣
10-1. TODOリストやIssueで未実装箇所を管理する
NotImplementedExceptionを残したまま忘れないためには、未実装箇所をTODOリストやIssueで管理することが大切です。
コード内に書くだけでは、後から見落とす可能性があります。
C#// TODO: ユーザー保存処理を実装する
throw new NotImplementedException();
このようなコードを書いた場合は、タスク管理ツールやIssueにも登録しておくと安心です。
「いつ」「誰が」「何を実装するのか」を明確にしておくことで、未実装コードの放置を防げます。
10-2. 単体テストで未実装コードを検出する
単体テストを用意すると、NotImplementedExceptionを早い段階で検出できます。
たとえば、次のようなテストがあるとします。
C#[TestMethod]
public void Add_2つの数値を加算できる()
{
var calculator = new Calculator();
int result = calculator.Add(10, 20);
Assert.AreEqual(30, result);
}
もしAddメソッドが未実装であれば、このテストはNotImplementedExceptionで失敗します。
単体テストは、未実装コードの発見だけでなく、実装後の動作確認にも役立ちます。
10-3. コードレビューでthrow文の残存を確認する
チーム開発では、コードレビューでNotImplementedExceptionが残っていないか確認しましょう。
レビュー時には、次のようなコードに注意します。
C#throw new NotImplementedException();
ただし、開発途中のブランチでは意図的に残している場合もあります。その場合は、Issueやコメントで管理されているか確認します。
本番にマージするコードでは、基本的にNotImplementedExceptionが残っていない状態が望ましいです。
10-4. 静的解析ツールを活用する
静的解析ツールを使うと、未実装コードや不要な例外を検出しやすくなります。
プロジェクトのルールとして、throw new NotImplementedException()が残っている場合に警告を出すように設定することもできます。
また、CI/CDのビルド時にチェックを入れることで、未実装コードが本番環境に入ることを防ぎやすくなります。
手作業の確認だけに頼らず、ツールで自動検出する仕組みを作ることが重要です。
10-5. リリース前チェックリストに追加する
NotImplementedExceptionの確認は、リリース前チェックリストに追加しておくと効果的です。
たとえば、次のような項目を用意します。
NotImplementedExceptionが残っていないか
TODOコメントに未対応の重要項目がないか
主要機能の単体テストが成功しているか
例外ログに未実装エラーが出ていないか
チェックリスト化しておくと、リリース直前の確認漏れを防げます。
特に初心者のうちは、作業のたびに覚えておくより、チェック項目として明文化する方が安全です。
11. NotImplementedExceptionに関するよくある質問
11-1. NotImplementedExceptionは削除してもよい?
NotImplementedExceptionは、必要な処理を実装したうえで削除するのが基本です。
単に削除するだけでは、メソッドが何もしなくなる可能性があります。
たとえば、次のコードがあります。
C#public void Save()
{
throw new NotImplementedException();
}
これを次のようにするだけでは不十分です。
C#public void Save()
{
}
保存処理が必要なら、実際に保存するコードを書く必要があります。
C#public void Save()
{
// 保存処理を書く
}
つまり、削除してよいかどうかではなく、「削除したあとに正しい処理が実装されているか」が重要です。
11-2. catchで処理すれば解決できる?
NotImplementedExceptionをcatchしても、根本的な解決にはなりません。
C#try
{
service.Execute();
}
catch (NotImplementedException)
{
Console.WriteLine("未実装です。");
}
このように書けば、アプリケーションの強制終了は防げるかもしれません。しかし、必要な処理が実行されていないことに変わりはありません。
NotImplementedExceptionは、通常「処理を実装することで解決する例外」です。例外処理で隠すのではなく、未実装箇所を修正しましょう。
11-3. TODOコメントとの違いは?
TODOコメントは、開発者向けのメモです。
C#// TODO: 入力チェックを追加する
NotImplementedExceptionは、実行時に例外を発生させます。
C#throw new NotImplementedException();
TODOコメントは実行に影響しません。一方、NotImplementedExceptionはその行が実行されるとプログラムが停止します。
未実装のメソッドを呼び出したらすぐ気づきたい場合はNotImplementedExceptionが有効です。軽い改善予定や後で見直すメモならTODOコメントが適しています。
11-4. 本番環境で発生した場合はどうすればよい?
本番環境でNotImplementedExceptionが発生した場合は、まずログを確認して発生箇所を特定します。
確認すべき情報は、例外メッセージ、スタックトレース、発生日時、ユーザーが行った操作、アプリケーションのバージョンなどです。
そのうえで、未実装のまま残っているコードを本実装に置き換える必要があります。
応急対応として、その機能を一時的に無効化することもあります。ただし、catchして握りつぶすだけでは根本解決にならないため、必ず修正版を用意しましょう。
11-5. 自作例外に置き換えるべきケースはある?
通常、単に未実装であることを示すだけならNotImplementedExceptionで十分です。
ただし、業務アプリケーションで独自のエラー分類やログ出力、ユーザー向けメッセージ制御が必要な場合は、自作例外を検討することもあります。
たとえば、特定の業務機能がまだ利用できないことを表す専用例外を作るケースです。
C#public class FeatureNotAvailableException : Exception
{
public FeatureNotAvailableException(string message) : base(message)
{
}
}
ただし、自作例外を増やしすぎると管理が複雑になります。まずは標準の例外で表現できるかを考え、それでも不足する場合に自作例外を検討するとよいでしょう。
まとめ
C#のNotImplementedExceptionは、「まだ実装されていない処理が呼び出された」ことを示す例外です。Visual Studioの自動生成コード、インターフェースの実装、抽象クラスの継承、サンプルコードなどでよく見かけます。
NotImplementedExceptionはコンパイルエラーではなく実行時エラーです。そのため、ビルドが成功していても、実行時に未実装メソッドが呼び出されると例外が発生します。
解決するには、まずスタックトレースやデバッグ機能で発生箇所を特定し、throw new NotImplementedException()を必要な処理に置き換えます。単に削除したり、catchで握りつぶしたりするのではなく、そのメソッドが本来行うべき処理を正しく実装することが重要です。
また、NotImplementedExceptionは開発途中の仮実装としては便利ですが、本番環境のコードに残すべきではありません。リリース前にはプロジェクト全体を検索し、未実装コードが残っていないか確認しましょう。
仕様上サポートしない処理にはNotSupportedException、現在の状態では実行できない処理にはInvalidOperationException、引数が不正な場合にはArgumentException系を使うなど、状況に応じて適切な例外を選ぶことも大切です。
NotImplementedExceptionの意味と使い方を正しく理解しておくと、C#開発で発生する実行時エラーの原因をすばやく特定でき、より安全で保守しやすいコードを書けるようになります。

