System.NullReferenceException: Object reference not set to an instance of an object. とは
C#開発者にとって「NullReferenceException」は最も頻繁に遭遇するエラーの一つです。このエラーは、null(何も参照していない状態)であるオブジェクトに対して、メンバー(メソッドやプロパティ)にアクセスしようとしたときに発生します。
エラーの発生パターン
このエラーは主に以下のようなケースで発生します。
パターン1: オブジェクトの初期化忘れ
public class User
{
public string Name { get; set; }
}
public class BadExample
{
public void DisplayUserName()
{
User user = null; // または new User() を忘れた場合
// user が null のため、Name プロパティにアクセスすると NullReferenceException
Console.WriteLine(user.Name);
}
}
user変数はnullで初期化されており、Userクラスのインスタンスが割り当てられていません。nullのオブジェクトに対してNameプロパティにアクセスしようとしたため、NullReferenceExceptionが発生します。
public class User
{
public string Name { get; set; }
}
public class GoodExample
{
public void DisplayUserName()
{
// オブジェクトを適切に初期化する
User user = new User { Name = "Alice" };
Console.WriteLine(user.Name);
}
}
パターン2: メソッドの戻り値がnull
public class UserService
{
public User GetUserById(int id)
{
// ユーザーが見つからない場合、null を返す
return null;
}
}
public class BadExample
{
public void ProcessUser()
{
UserService service = new UserService();
User user = service.GetUserById(1);
// user が null の可能性があるため、Name プロパティにアクセスすると NullReferenceException
Console.WriteLine(user.Name);
}
}
GetUserByIdメソッドがnullを返した場合、user変数にはnullが格納されます。そのnullに対してNameプロパティにアクセスすると、NullReferenceExceptionが発生します。
public class UserService
{
public User GetUserById(int id)
{
return null;
}
}
public class GoodExample
{
public void ProcessUser()
{
UserService service = new UserService();
User user = service.GetUserById(1);
// null チェックを行ってからメンバーにアクセス
if (user != null)
{
Console.WriteLine(user.Name);
}
else
{
Console.WriteLine("ユーザーが見つかりません。");
}
}
}
パターン3: イベントハンドラがnull
public class BadExample
{
// イベントに購読者が登録されていない可能性がある
public event Action MyEvent;
public void RaiseEvent()
{
// MyEvent が null の場合、NullReferenceException
MyEvent();
}
}
MyEventイベントに購読者(ハンドラ)が登録されていない場合、MyEventはnullになります。nullのデリゲートを呼び出そうとしたため、NullReferenceExceptionが発生します。
public class GoodExample
{
public event Action MyEvent;
public void RaiseEvent()
{
// C# 6.0 以降の null 条件演算子 (?. ) を使用
MyEvent?.Invoke();
// 以前の C# バージョンでは以下の方法
// var handler = MyEvent;
// if (handler != null)
// {
// handler();
// }
}
}
根本原因の特定方法
NullReferenceExceptionが発生した行で、どのオブジェクトがnullであるかを確認してください。IDEのデバッガでブレークポイントを設定し、ステップ実行しながら関連する変数の値を確認すると原因を特定しやすいです。
public class DebugExample
{
public User GetUser() { return null; }
public void DebugMethod()
{
User user = GetUser(); // このメソッドが null を返す可能性がある
// ここで user が null であることを確認
if (user == null)
{
Console.WriteLine("user is null at this point.");
}
// この行で NullReferenceException が発生する可能性
// Console.WriteLine(user.Name);
}
}
防止策とベストプラクティス
オブジェクトにアクセスする前には、必ずnullチェックを行う習慣をつけましょう。C# 6.0以降のnull条件演算子 (?. ) やnull合体演算子 (?? ) を活用することで、簡潔かつ安全にコードを記述できます。
public class PreventionExample
{
public User GetUser() { return null; }
public void SafeAccess()
{
User user = GetUser();
// null 条件演算子と null 合体演算子の組み合わせ
string userName = user?.Name ?? "Unknown";
Console.WriteLine(userName);
// Nullable Reference Types を使用 (C# 8.0+)
// #nullable enable をファイル先頭に追加
// User? nullableUser = GetUser();
// if (nullableUser != null)
// {
// Console.WriteLine(nullableUser.Name);
// }
}
}
よくある質問(FAQ)
-
QNullReferenceExceptionとArgumentNullExceptionの違いは何ですか?
-
A
NullReferenceExceptionはnullオブジェクトのメンバーにアクセスしたときに発生します。ArgumentNullExceptionは、メソッドに渡された引数がnullであるべきではないにもかかわらずnullだった場合に、そのメソッド内で明示的にスローされる例外です。
-
QNullable Reference Types (NRT) はどのように役立ちますか?
-
A
NRTは、参照型がnullを許容するかどうかをコードで明示的に示すことで、コンパイル時に潜在的なNullReferenceExceptionを警告します。これにより、実行時エラーを未然に防ぎやすくなります。
-
Qnull条件演算子 (?. ) とnull合体演算子 (??) はどのように使い分けますか?
-
A
null条件演算子 (
?.) は、オブジェクトがnullでない場合にのみメンバーアクセスを実行し、結果がnullになりえます。null合体演算子 (??) は、左側のオペランドがnullの場合に右側のオペランドの値を返します。?.で安全にアクセスし、その結果がnullだった場合に??でデフォルト値を設定するのが一般的です。




コメント