C#でアプリケーションを開発している際、実行時に「System.NotImplementedException: The method or operation is not implemented.」というメッセージと共にプログラムが停止してしまうことがあります。
この例外は、呼び出されたメソッドやプロパティの実装がまだ記述されていないことを示す、.NET環境における標準的な実行時エラーの一つです。
Visual Studioなどの開発環境でインターフェースを自動実装した際などに、デフォルトでこの例外をスローするコードが生成されるため、開発初期段階では頻繁に遭遇することになります。
本記事では、この例外が発生する根本的な原因から、適切な対処法、そしてコードの品質を保つための設計上の注意点までを詳しく解説します。
System.NotImplementedExceptionとは何か
System.NotImplementedExceptionは、特定のメソッド、プロパティ、または操作の実装が未完了であることを明示するために使用される例外クラスです。
この例外はSystem名前空間に定義されており、すべての実行時例外の基底となるExceptionクラスを継承しています。
このエラーが発生したということは、プログラムが「その機能が必要であること」を認識して呼び出しましたが、具体的な処理の内容がまだ一行も書かれていない状態であることを意味します。
多くの場合、開発の利便性を高めるためのプレースホルダー(仮置き)として利用されますが、本番環境でこの例外がスローされることは避けるべき設計上の課題と言えます。
この例外が発生する主な原因
開発中にSystem.NotImplementedExceptionが発生するシチュエーションは、主に以下の3つのパターンに集約されます。
1. IDEによるインターフェースの実装生成
Visual Studioなどの統合開発環境(IDE)において、インターフェースをクラスに適用し、クイックアクションを使ってスタブ(代用コード)を生成した場合、この例外が自動的に挿入されます。
例えば、以下のコードのようにIDataProcessorインターフェースを実装した直後の状態がこれに該当します。
// インターフェースの定義
public interface IDataProcessor
{
void ProcessData(int id);
}
// IDEによって自動生成されたクラスの実装
public class MyDataProcessor : IDataProcessor
{
public void ProcessData(int id)
{
// 自動生成された時点ではこの行が挿入されている
throw new NotImplementedException();
}
}
この状態のままメソッドを呼び出すと、実行時に例外がスローされます。
var processor = new MyDataProcessor();
processor.ProcessData(100); // ここでSystem.NotImplementedExceptionが発生
Unhandled exception. System.NotImplementedException: The method or operation is not implemented.
at MyDataProcessor.ProcessData(Int32 id) in Program.cs:line 15
2. 抽象クラスの継承と実装漏れ
抽象クラス(abstract class)を継承した派生クラスにおいて、抽象メソッドをオーバーライドした際にも、同様のスタブコードが生成されることがあります。
開発者は「後で実装しよう」と考えてそのまま放置してしまい、ユニットテストや実際の動作確認中にこのエラーに直面することが少なくありません。
3. 将来的な拡張のための定義
設計段階で、将来的に必要になることが分かっている機能をメソッド名として定義だけしておき、「まだ着手していないこと」を忘れないようにあえて例外をスローするように記述しておくケースです。
NotImplementedExceptionへの適切な対処法
この例外が発生した際、単にコードを書き足すだけでなく、そのメソッドが本来どのような状態であるべきかを検討する必要があります。
1. ロジックを正しく実装する
最も基本的な解決策は、本来意図していた処理を記述することです。
自動生成されたthrow new NotImplementedException();の一行を削除し、必要なビジネスロジックを実装してください。
2. 未実装であることを示すコメントを残す
もし意図的に実装を後回しにする場合は、単に例外を投げるだけでなく、TODOコメントを併記しておくことが推奨されます。
public void SaveChanges()
{
// TODO: データベースへの保存ロジックを2026年度第2四半期中に実装予定
throw new NotImplementedException("データベース連携機能は現在開発中です。");
}
例外のコンストラクタにメッセージを渡すことで、デバッグ時に「なぜ未実装なのか」を把握しやすくなります。
3. デフォルトの実装を提供する(C# 8.0以降)
C# 8.0以降では、インターフェースに「デフォルトインターフェースメソッド」を定義できるようになりました。
全てのクラスで必ずしも実装が必要ない場合は、インターフェース側で空の処理やデフォルトの挙動を定義することで、例外の発生を回避できます。
public interface ILogger
{
void Log(string message);
// デフォルトの実装を定義
void LogError(string message) => Log($"Error: {message}");
}
NotSupportedExceptionとの違いと使い分け
System.NotImplementedExceptionと混同されやすい例外に、System.NotSupportedExceptionがあります。
この二つは意味が明確に異なるため、正しく使い分けることが重要です。
| 例外名 | 意味 | 主な発生理由 |
|---|---|---|
| NotImplementedException | 未実装である(将来実装される可能性がある) | 開発中の機能、IDEによる自動生成、作業の忘れ。 |
| NotSupportedException | サポートされていない(実装する意図がない) | 読み取り専用ストリームへの書き込み、特定のプラットフォームで非対応な機能。 |
例えば、インターフェースで定義されているメソッドのうち、特定の具象クラスでは「原理上、絶対に提供しない機能」がある場合は、NotImplementedExceptionではなくNotSupportedExceptionを使用すべきです。
これにより、他の開発者は「このメソッドは後で実装されるのではなく、このクラスでは使えない設計なのだ」と正しく理解できます。
設計上の注意点とベストプラクティス
System.NotImplementedExceptionがプロジェクトのコードベースに残り続けることは、潜在的なバグを抱えているのと同じです。
静的解析ツールの活用
Visual Studioのコード解析機能や、外部の静的解析ツール(SonarQubeなど)を使用すると、NotImplementedExceptionが残っている箇所を警告としてリストアップできます。
CI/CDパイプラインにおいて、これらの例外が含まれるコードがマージされないようにチェックをかける運用が効果的です。
ユニットテストでの検出
すべての公開メソッドに対してユニットテストを作成することで、未実装のパスを通った際にテストが失敗し、リリース前に問題を確実に検知できます。
テスト駆動開発(TDD)を採用している場合、最初はテストを失敗させるためにあえてNotImplementedExceptionを投げさせ、それを実装で埋めていくというサイクルが自然に形成されます。
インターフェース分離の原則(ISP)
もし特定のクラスで多くのメソッドがNotImplementedExceptionを投げているのであれば、それはインターフェースが大きすぎる(肥大化している)サインかもしれません。
「インターフェース分離の原則」に従い、インターフェースをより小さな単位に分割することで、不要なメソッドの実装を強制されることがなくなります。
まとめ
System.NotImplementedExceptionは、C#開発において非常に身近な例外であり、実装の進捗を管理するための道標でもあります。
IDEが自動的に生成したコードをそのままにせず、適切なロジックを実装するか、あるいは設計を見直して適切な例外を選択することが重要です。
開発の過程でこのエラーに遭遇した際は、それが「単なる実装忘れ」なのか「設計上の不備」なのかを冷静に判断しましょう。
エラーメッセージを正しく読み解き、適切な対処を行うことで、アプリケーションの堅牢性と信頼性は格段に向上します。
高品質なC#プログラムを目指すために、未実装のコードを放置せず、常に完了した状態を維持する習慣を身につけていきましょう。
