なぜ「オブジェクト参照がオブジェクトのインスタンスに設定されていない」とどのオブジェクトがわからないのですか?


39

私たちはシステムを立ち上げており、時々NullReferenceExceptionメッセージで有名な例外を受け取りますObject reference not set to an instance of an object

しかし、ほぼ20個のオブジェクトがあるメソッドでは、オブジェクトがnullであると言うログを持つことは、まったく役に立ちません。あなたがセミナーの警備員であるとき、100人の出席者のうちの1人がテロリストであるとあなたに言うようなものです。それは本当にあなたにはまったく役に立ちません。どの男が脅迫的な男であるかを検出したい場合は、より多くの情報を取得する必要があります。

同様に、バグを削除する場合は、どのオブジェクトがnullであるかを知る必要があります。

今、何かが私の心を数ヶ月の間取りつづけています、そしてそれは:

なぜ.NETから名前、または少なくともオブジェクト参照のタイプが提供されないのですか?。リフレクションまたは他のソースからタイプを理解できませんか?

また、どのオブジェクトがnullであるかを理解するためのベストプラクティスは何ですか?これらのコンテキスト内のオブジェクトのNULL可能性を常に手動でテストし、結果をログに記録する必要がありますか?もっと良い方法はありますか?

更新: 例外The system cannot find the file specifiedは同じ性質を持っています。プロセスにアタッチしてデバッグするまで、どのファイルを見つけることができません。これらのタイプの例外はよりインテリジェントになる可能性があると思います。.NETがc:\temp.txt doesn't exist.その一般的なメッセージの代わりに私たちに伝えることができたらもっと良いと思いませんか?開発者として、私は賛成票を投じます。


14
例外には、行番号付きのスタックトレースを含める必要があります。その行でアクセスされるすべてのオブジェクトを見て、そこから調査を開始します。
PersonalNexus

2
また、Visual Studioの例外ヘルパーダイアログにnew、クラスのインスタンスを作成するために使用する「役立つ」ヒントが含まれている理由を常に疑問に思っていました。このようなヒントはいつ本当に役立つのでしょうか?
PersonalNexus

1
10個のオブジェクト呼び出しのチェーンがある場合、設計でのカップリングに問題があります。
ピートカーカム


9
この質問に対するすべての回答が、「デバッガを使用し、エラーをログに記録し、nullをチェックします。とにかくあなたのせいです」という行に沿っているのが大好きです。stackoverflowでのみ、誰かが実際に答えを出します(VMが追跡するにはオーバーヘッドが大きすぎると思います)。しかし、実際には、この質問に適切に答えることができるのは、フレームワークに取り組んだマイクロソフトの誰かだけです。
ロックラン

回答:


28

NullReferenceException基本的に説明します:あなたは間違ってそれをやっています。これ以上でもそれ以下でもありません。それどころか、本格的なデバッグツールではありません。この場合、あなたは両方とも間違っていると言います

  • NullReferenceExceptionがあります
  • なぜ/どこでそれが起こったかを知る方法でそれを防げなかった
  • また多分:20個のオブジェクトを必要とするメソッドは少しオフに見える

私は、物事がうまくいかなくなる前にすべてをチェックし、開発者に良い情報を提供することの大ファンです。要するに:ArgumentNullExceptionといいねを使ってチェックを書き、自分で名前を書きます。サンプルを次に示します。

void Method(string a, SomeObject b)
{
    if (a == null) throw ArgumentNullException("a");
    if (b == null) throw ArgumentNullException("b");

    // See how nice this is, and what peace of mind this provides? As long as
    // nothing modifies a or b you can use them here and be 100% sure they're not
    // null. Should they be when entering the method, at least you know which one
    // is null.
    var c = FetchSomeObject();
    if(c == null)
    {
        throw InvalidOperationException("Fetching B failed!!");
    }

    // etc.
}

また、コードコントラクトを調べることもできます。


17
@SaeedNeamatiあなたは大規模なコードベースを持っているので、まともなエラーチェックを行うべきではないことを暗示していませんよね?Imoは、プロジェクトが大きいほど、役割またはエラーのチェックとレポートが重要になります。
stijn

6
実際の質問(おそらくAnders Hejlsbergだけが答えることができる)に答えない場合でも、良いアドバイスを得るために+1。
ロスパターソン

12
素晴らしいアドバイスのために+1。@SaeedNeamatiこのアドバイスを聞いてください。あなたの問題は、コードの不注意とプロ意識の欠如が原因です。適切なコードを作成する時間がない場合は、さらに大きな問題が発生します
...-MattDavey

3
良いコードを書く時間がなければ、間違いなく悪いコードを書く時間はありません。悪いコードを書くことは、良いコードを書くよりも時間がかかります。本当にバグを気にしない限り。そして、もしあなたが本当にバグを気にしないのであれば、なぜプログラムを書くのでしょうか?
MarkJ

5
@SaeedNeamati I only say that checking every object to get sure that it's not null, is not a good methodマジ。それが最良の方法です。また、nullだけでなく、すべての引数で妥当な値を確認してください。エラーを早期に発見すればするほど、原因を見つけやすくなります。原因となる呼び出しを見つけるために、スタックトレースのいくつかのレベルをバックトラックする必要はありません。
jgauffin

19

それは本当にあなたが呼ぼうとしていることを正確に示すはずです。「問題があります。あなたはそれを修正する必要があります。私はそれが何であるかを知っています。私はあなたにそれを伝えません。あなたはそれを理解します。」

たとえば、これを手に入れたら...

Object reference (HttpContext.Current) not set to instance of an object

...?コードに入り、ステップスルーし、あなたが呼ぼうとしていることnullは問題ないことを理解する必要がありますが、なぜ私たちにちょっとした助けを与えてはいけませんか?

答えを得るためにコードをステップスルーすることは通常有用であることに同意します(おそらくもっと詳しく知るでしょう)が、多くの場合、NullReferenceExceptionテキストが上記の例のようであれば、多くの時間とフラストレーションが節約されます。

言ってるだけ。


ランタイムはどのようにnullが何であるかを知ることになっていますか?
ウィル

3
ランタイムには、提供されるより多くの情報があります。どんな有用な情報を持っているとしても、それは提供されるべきです。私が言っているのはそれだけです。あなたの質問に答えて、なぜ知らないのですか?その答えを知っていれば、あなたが持っているよりも良いコメントを提供できるかもしれません。
LiverpoolsNumber9

同意し、KeyNotFoundException他の多くの迷惑についても同じことを言うでしょう
...-sinelaw

実際、nullの逆参照の場合、これはCLRが逆参照する方法の制限のように見えます(OPの質問に対するShahrooz Jefriのコメントのおかげです)
sinelaw


4

ログにはスタックトレースが含まれている必要があります。これにより、通常、メソッドのどの行に問題があるかについてのヒントが得られます。エラーが発生している行を把握できるように、リリースビルドにPDBシンボルを含める必要がある場合があります。

確かに、この場合は役に立ちません:

Foo.Bar.Baz.DoSomething()

TELLは質問しないようなコードを避けるために、原則缶の助けを。

なぜ情報が含まれていないのかはわかりません-少なくともデバッグビルドでは、本当に望むなら、それを理解できると思います。クラッシュダンプを取得してWinDBGで開くと役立つ場合があります。


2

例外は、コールチェーンの上位の例外的で致命的でない状態を通知するツールとして作成されました。つまり、デバッグツールとして設計されていません。

ヌルポインター例外がデバッグツールである場合、その場でプログラムの実行を中止し、デバッガーが接続して、問題のある行を指すようにします。これにより、利用可能なすべてのコンテキスト情報がプログラマに提供されます。(少し粗雑ではありますが、ヌルポインターアクセスによるセグメンテーション違反がCで行うことはほとんどあります。)

ただし、nullポインター例外は、通常のプログラムフローでスローおよびキャッチできる有効なランタイム条件として設計されています。したがって、パフォーマンスの考慮事項を考慮する必要があります。また、例外メッセージをカスタマイズするには、実行時に文字列オブジェクトを作成、連結、および破棄する必要があります。そのため、静的メッセージは間違いなく高速です。

ただし、原因となる参照の名前を生成するような方法でランタイムをプログラムできなかったとは言っていません。それができました。例外が実際よりも遅くなるだけです。誰かが十分に気をつけていれば、そのような機能を切り替え可能にすることもできます。そのため、実動コードの速度を落とすことはありませんが、デバッグは容易になります。しかし、何らかの理由で、誰も十分に世話をしていないようです。


1

Cromulentは頭に釘を打ちましたが、もしあなたが取得しているNullReferenceException場合、初期化されていない変数があるという明らかなポイントもあります。メソッドに渡される約20個のオブジェクトを持っているという議論は、緩和とは言えません。コードチャンクの作成者は、コードベースの残りの部分への準拠を含めて、その動作に対して責任を負う必要があります。変数などの適切かつ正しい利用

面倒で退屈で時々退屈ですが、最後の報酬には価値があります。多くの場合、数ギガバイトのログファイルを探し回らなければならず、ほとんどの場合に役立ちます。ただし、その段階に到達する前に、デバッガーが役立ちます。その段階の前に、適切な計画を立てることで多くの苦痛を軽減できます(そして、単純なスケッチといくつかのメモができ、また、何もないよりはましだ)。

Object reference not set to an instance of an objectコードに関しては、私たちが好きな値を推測することはできません。それはプログラマとしての私たちの仕事であり、初期化されていない変数を渡したということです。


アセンブリ言語で書くためにこのような正当化を提供するために使用される人々を知っていますか?自動ガベージコレクションを使用していませんか?そして、算術ができる-16進数で?「面倒で退屈で、時にはつまらない」とは、自動化されるべきジョブを説明する方法です。
Spike0xff

0

デバッガーの使用方法を学びます。これはまさにそれが設計されたものです。問題のメソッドにブレークポイントを設定して、離れます。

コードをステップ実行するだけで、特定のポイントですべての変数の値が正確に何であるかを確認できます。

編集:率直に言って、デバッガーの使用についてまだ誰も言及していないことにショックを受けました。


2
デバッガーを使用すると、すべての例外を簡単に再現できると言っていますか?
jgauffin

@jgauffinは、デバッガを使用して、問題のコードを実際に完全にテストしないかもしれない合成ユニットテストではなく、実際のコードで例外がスローされる理由を確認できる、またはユニットテスト自体に原因があるバグがあると言っている実際のコードのバグを見逃します。デバッガーは、私が考えることのできる他のあらゆるツールよりも優れています(ValgrindやDTraceなどを除く)。
Cromulent

1
失敗したコンピューターには常にアクセスでき、デバッグは単体テストよりも優れていると言っていますか?
jgauffin

@jgauffin選択肢があれば、他のツールよりもデバッガーを優先して使用します。もちろん、あなたがその選択を持っていないなら、それは少し非スターターです。明らかにこれはこの質問には当てはまらないので、私が答えたのはこのためです。リモートデバッグ(またはローカルデバッグ)を行う方法がないクライアントコンピューターでこの問題をどのように修正するのかという質問があった場合、私の答えは異なります。手元の質問に関係のない方法で私の答えをゆがめようとしているようです。
Cromulent

0

@stijnの回答に進み、コードにnullチェックを入れたい場合は、このコードスニペットが役立ちます。 コードスニペットに関する情報を次に示します。これを設定したら、を入力するだけでargnull、タブを2回押してから空白を埋めます。

<CodeSnippet Format="1.0.0">
  <Header>
    <Title>EnsureArgNotNull</Title>
    <Shortcut>argnull</Shortcut>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>argument</ID>
        <ToolTip>The name of the argument that shouldn't be null</ToolTip>
        <Default>arg</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[if ($argument$ == null) throw new ArgumentNullException("$argument$");$end$]]>
    </Code>
  </Snippet>
</CodeSnippet>

注:C#6今持っているnameofあなたのスニペットは可能性がありので、throw new ArgumentNullException(nameof($argument$))コンパイラによってチェックされている魔法の定数、含まないの利点を有している、およびリファクタリングツールを使って、より良い作業
stijn
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.