2009-02-23 11 views
11

複雑なステートメントでヌル参照例外を追いかけるのに、多くのデバッグ時間が費やされているようです。例えば:私はとNullReferenceExceptionを得るときヌル参照を持つオブジェクトにヌル参照例外の名前を付けることができないのはなぜですか?

For Each game As IHomeGame in _GamesToOpen.GetIterator() 

はなぜ、私は、スタックトレースの行番号ではなく、ヌル等しいオブジェクトの名前を取得することができます。言い換えれば、なぜ:

Object reference not set to an instance of an object. 

代わりの

_GamesToOpen is not set to an instance of an object. 

または

Anonymous object returned by _GamesToOpen.GetIterator() is null. 

または

game was set to null. 

これは厳密には匿名性を保護するためのもので、設計上の選択であり、またはコードがありますか?デバッグ時の例外にこの情報を含まないようにするコンパイラ設計の理由は何ですか?

答えて

11

例外は実行時のものです。変数はコンパイル時のものです。

実際、例の変数はの式です。式は必ずしも単純変数ではない。実行時に式が評価され、結果のオブジェクトに対してメソッドが呼び出されます。その式の値がnullの場合、実行時にNullReferenceExceptionがスローされます。次のことを想定します

Dim a as New MyObject 
Dim b as String = MyObject.GetNullValue().ToString() 

GetNullValue()方法はnullを返した場合どのようなエラーメッセージべきランタイム復帰?

+2

行番号も実行時のものです。デバッグ時のコンパイルには、あらゆる種類のコンパイル時のもの(クラス名やメソッド名、行番号など)が含まれています。 –

+1

クラスとメソッド、およびパラメータ名は実際にILレベルで存在します。しかし、生成されたILでは、変数はほとんどなくなっています。基本的には、特定の変数に例外を関連付ける特別な方法はありません。「if(a

+0

上記のコメントのために受け入れられました。 –

1

オブジェクトを使用する前に、Assertステートメントを配置するデバッグのためにこれをキャッチする簡単な方法は、nullをチェックして意味のあるメッセージを出力します。

+0

アサートを持つことは常に可能ではありません。たとえば、Linq式の内部にアサートを追加することはできません。 –

+0

私が間違っている場合は私を修正しますが、最適化されたリリースビルドからAssertステートメントが削除されたと考えました。 – Marc

1

リリースビルドでは、変数名がシンボルから除外され、コードは変数の特定のメモリ位置を持たないように最適化されていても、レジスタの1つに参照を保持するだけです変数の使用方法の説明)。したがって、参照場所から変数の名前を差し引くことはできない可能性があります。

デバッグビルドでは、変数についてより多くの情報があります。ただし、例外オブジェクトはビルドフレーバに関係なく同じ方法で動作する必要があります。したがって、どのフレーバでもアクセスできる最小限の情報に基づいて動作します。

+0

これは問題ありません。とにかくあなたはリリースビルドでそれを望んでいないでしょう。私は、なぜあなたがデバッグビルドでこれを見ることができないのだろうと疑問に思っていたことを質問に明記しました。 –

+0

私はこれを言いましたが。例外オブジェクトはデバッグ機能ではなく、ビルドフレーバに関係なく同じ動作をする必要があります。あなたは、デバッグフレーバーの下で、文字列クラスの動作が根本的に変わるとは思わないでしょうか? –

1

物事のカップル...

1)あなたがあなた自身の例外を作るあなたがイライラしている場合は、何か他のもののためにそれを行う場合は、他の本の誰かのためにそれ、それはあなたに迷惑になります(これを覚えておきます)。例外パスが典型的なパスであってはならないことを考えれば、例外を作るのに費やされた時間は有益な情報を持っている価値があります。一般的なプログラミングpractiveのよう

2)このスタイルを採用し、あなたがはるかに少ない問題を持っています(はい、あなたのコードは、行の面でより長くなりますが、あなたは多くの時間を節約します):

a)は決してdo()。c(); do do x = a.b();バツ。c(); (別の行に)、aがnullであるか、a.b()の戻り値がnullであるかを見ることができます。

b)パラメータとしてメソッド呼び出しの戻り値を渡すことは決してありません。常に変数を渡します。 a(foo()); x = foo();でなければなりません。斧);これは、デバッグと値を見ることができます。

.NETやJavaなどの環境で、これらの種類の例外に関する詳細情報を持つランタイムバージョンが提供されない理由はわかりません。たとえば、インデックスが配列外にある配列、名前それがnullである変数、等...の

VMによって解釈されますバイトコードにコンパイルされたJavaのような言語の場合
2

は、あなたがフィールドxでクラスXがあるとし、その値がためnullです特定の参照。あなたは

x.foo() 

を記述する場合、バイトコードは次のようになります。

push Xref   >> top of stack is ref to instance of X with X.x = null 
getField x   >> pops Xref, pushes 'null' on the stack 
invokeMethod foo >> pops 'null' -> runtime exception 

ポイントスタック上の非null参照を必要とする操作を例には、invokeMethodのように、その上で動作するということですそのnullリファレンスがどこから来たのか分からない。

関連する問題