オブジェクト参照がオブジェクトのインスタンスに設定されていません。なぜ.NETはどのオブジェクトが「null」であるかを表示しないのですか?


103

この.NETの未処理の例外メッセージについて:

オブジェクト参照がオブジェクトインスタンスに設定されていません。

.NETがどのオブジェクトであるかを表示しないのはなぜですか nullかをですか?

nullエラーを確認して解決できることはわかっています。しかし、なぜ.NETは、どのオブジェクトがnull参照を持ち、どの式がトリガーされたNullReferenceExceptionかを指摘できないのですか?

c#  .net 

2
これが発生した場合、発生した行を書き直して、考えられる結果ごとに最初にnullをチェックします。そうすると、それが正確に何であるかがわかります。どちらかその、またはインスタントを破る付属のVisual Studioの素晴らしいデバッガを、持っている例外が発生したとすることができます、あなたがnullであるかを見る:)
Patashu

5
実際はそうではありません。彼は、.NET Frameworkがプログラマーがどのオブジェクトがnullであるかを示すの助けないのかを単に尋ねます。それはパフォーマンスの低下だと思います(リフレクションが必要です)。しかし、どちらかわかりません。
bas 2013

1
@bas:それは真実ですが、質問は「オブジェクト」ではなく「式の一部」について尋ねるべきであるという点で少し誤解を招きます。これは、単なるリフレクションが役に立たない理由も説明しますが、いくつかの広範なデバッグ情報が必要になります。
ORマッパー2013

4
それでも私は答えに興味があります。これは、どのキーが辞書に存在しないを指摘できない.netの例外と似てます。また、質問への献身がわかりません。
bas 2013

12
用語集:オブジェクトがnullになることはありません。オブジェクト参照はいえかもしれません。しかし、オブジェクト参照はメモリ内の単なる場所です-とにかくデバッガを接続していない限り、それはどのように役立ちますか?
Oskar Berggren 2013

回答:


169

(Visual Studio 2017の新しい例外ヘルパーについては、この回答の最後を参照してください)


このコードを考えてみましょう:

String s = null;
Console.WriteLine(s.Length);

これはNullReferenceException、2行目にをスローし、.NETがそれがsがスローされ、例外がスローされたときにnullことが。

なぜそのような情報が得られないのかを理解するには、実行するのはC#ソースではなくILであることを覚えておく必要があります。

IL_0001:ldnull      
IL_0002:stloc.0 // s
IL_0003:ldloc.0 // s
IL_0004:callvirt System.String.get_Length
IL_0009:System.Console.WriteLineを呼び出します

callvirtをスローするのはオペコードでありNullReferenceException、評価スタックの最初の引数がnull参照(を使用してロードされたものldloc.0)である場合にそれを行います。

.NETがsそれがnull参照であったことを認識できる必要がある場合は、評価スタックの最初の引数がフォームから発生したことを何らかの方法で追跡する必要がありますs。この場合、それsがnullであることが簡単にわかりますが、値が別の関数呼び出しからの戻り値であり、変数に格納されていない場合はどうなりますか?とにかく、この種の情報は、.NET仮想マシンのような仮想マシンで追跡したいものではありません。


この問題を回避するには、すべてのパブリックメソッド呼び出しで引数のnullチェックを実行することをお勧めします(もちろん、null参照を許可しない限り)。

public void Foo(String s) {
  if (s == null)
    throw new ArgumentNullException("s");
  Console.WriteLine(s.Length);
}

nullがメソッドに渡されると、問題が何であるかを正確に説明する例外(つまりsnull)が発生します。


4年後のVisual Studio 2017には、a NullReferenceExceptionがスローされたときにnullが何であるかを通知する新しい例外ヘルパーが追加されました。nullであるメソッドの戻り値である場合は、必要な情報を提供することもできます。

Visual Studio 2017例外ヘルパー

これはDEBUGビルドでのみ機能することに注意してください。


5
行番号とソースファイル名もILコード自体に格納されていませんか、それともそうですか?ただし、デバッグに使用できます。
またはMapper

4
@MartinLiversage:その通りです。つまり、問題は次のように要約されます。シンボルファイルに保存されている十分な情報がないので、コード内のどの式が評価されたかがわかりnullます。
またはMapper

2
@MartinLiversage:シンボルファイルは、例外時に例外メッセージとともにソースファイルと行番号をデバッガの出力に表示できるようにアクセスできます。したがって、問題は、正確に何が返されたのかについての詳細情報を含めない理由は何ですか?nullOPはリリースビルドについてもデバッグビルドで十分であると彼/彼女が知りたいと主張していないことに注意してください。
ORマッパー2013

3
ええと、実際に実行されるのはILでもなく、実行時にそこからビルドされるネイティブコードであることを忘れないでください。
Oskar Berggren

2
@MartinLiversage:この質問の誰も、リリースビルドでこれを完全にサポートしたいとは思っていません。とにかく、オブジェクト参照を使用するILオペコード(となる可能性があるnull)を、そのオブジェクト参照を返したソースファイルの行と列に関連付ける際に問題が発生することはあまりありません。
ORマッパー2013

9

次の場合のエラーメッセージをどのように表示しますか?

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}

ここに報告する変数名はありません!


2
OPがオブジェクトではなく、nullを返すソースコード内の式を探しているのではないかと思います。私は質問にそれぞれのコメントを追加しました、そして彼または彼女が事を片付けることを望みます。私の疑いが正しければ、OPはObject reference obtained from AnyObject.GetANullObject() not set to an instance of an object.エラーメッセージとして何かを期待します。
またはMapper

1
@ORMapper同意する。コメントを追加するのに十分な評判ポイントがあれば、私はOPへのコメントに私の「答え」を入れるだけでした。
romar 2013

1
「クラスXYZのToString()メソッドを呼び出そうとするnull参照」は、現在得られるものよりも役立つでしょう。
マイケルレビー

最も役立つのは、各呼び出しレベルで、どのファイルのどの行がエラーを引き起こしたかを正確に示すスタックトレースです。ああ、待ってください...それが今やっていることです!
ジムバルター、2015

1

ええと、それはMicrosoftのエンジニアの答えです。ただし、デバッガを使用してウォッチを追加し、問題のあるものを見つけることはできます。

ただし、例外はNullReferenceException、参照が存在しないことを意味します。まだ作成されていないオブジェクトは取得できません。

but why .NET don't tell us which object is null? これは、どのオブジェクトがnullであるかを認識していないためです。オブジェクトは単に存在しません!

私が言う場合も同じです。C#は.NET ILコードにコンパイルされます。.NET ILコードは名前または式を認識しません。参照とその場所のみを認識します。ここでも、存在しないものを手に入れることはできません。式または変数名が存在しません。

哲学:そもそも卵がないとオムレツは作れません。


3
それも答えではない:)
bas

参照が存在しない場合、どのようにして参照を取得しますか?@Bas
Aniket Inge

4
「そうですね、それはマイクロソフトのエンジニアが答えるのです。」それで、明白なことを述べる代わりに、彼らにこれに光を当てましょう
bas

@basは、少なくとも論理的なものを決定できます。論理的にはオブジェクトは存在しません。どのようにして例外でそれをキャッチし、オブジェクトの名前を出力しますか?それは存在しません。スタック上にもない..
Aniket Inge 2013

答えは、どのオブジェクトがnull参照を持つかを指摘することは事実上不可能であることです。それも答えです。私は知っていることを述べていません、私は質問が好きです:)。すべての努力に+1:p
bas

1

確かではありませんが、これは、.Netが事前定義されたクラスであるかユーザー定義であるかを認識していないためである可能性があります。事前定義されている場合はnull(2バイトを占有する文字列のように)にすることもできますが、ユーザー定義の場合は、このオブジェクトがこの大量のメモリを占有することがわかるようにインスタンスを作成する必要があります。したがって、実行時にエラーがスローされます。


-2

良い質問。メッセージボックスは役に立たないだけです。参照定義から1マイルの深さで埋め込まれている場合でも、一部のクラス、アセンブリ、ファイル、またはその他の情報は、それらが現在提供しているものよりも優れています(読み取り:何もないよりはまし)。

最善のオプションは、デバッグ情報を使用してデバッガーで実行することです。IDEは問題のある行で中断します(実際に有用な情報が実際に利用可能であることを明確に示します)。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.