web-dev-qa-db-ja.com

C#:オブジェクト変数をnullに割り当てる必要がありますか?

C#では、オブジェクト変数をnullに割り当てる必要はありますか?とにかくそれがスコープから外れる場合でも、それを使い終わったら

46
Craig Johnston

いいえ、実際には危険でバグが発生しやすい可能性があります(nullに設定されていることに気付かずに、後で誰かがそれを使用しようとする可能性を考慮してください)。 nullに設定する論理的な理由がある場合にのみ、何かをnullに設定します。

38
Daniel DiPaolo

さらに重要なのは、IDisposableを実装するオブジェクトでDisposeを呼び出すことです。

それとは別に、nullを参照変数に割り当てると、コンパイラー/ JIT最適化の時代に、スコープの終わり(ほとんどの場合、そのわずかな命令(たとえば、メソッド本体のローカル変数))が明示的に示されますランタイムが同じことをする可能性が非常に高いので、実際には何もしません。静的変数など(スコープがアプリケーションレベルであるなど)の場合は、オブジェクトのガベージコレクションが行われるように変数を使用し終わった場合は、変数をnullに割り当てる必要があります。

27
VinayC

湖に押し込む前に車を止めるべきですか?
番号。これはよくある間違いですが、違いはありません。 objectをnullに設定せず、1つだけreferenceをnullに設定します。オブジェクトはまだメモリ内にあり、ガベージコレクターによって収集する必要があります。

24
Kobi

これらの応答のほとんどは正しい答えを持っていますが、間違った理由があります。

ローカル変数の場合、変数はメソッドの最後でスタックから外れるため、参照していたオブジェクトの参照は1つ少なくなります。その変数がオブジェクトへの唯一の参照である場合、オブジェクトはGCで使用できます。

変数をnullに設定すると(メソッドの最後にそうするように教えられた人の多くが)、オブジェクトがメモリに留まる時間を延長することになります。CLRはオブジェクトはそこにあるオブジェクトへのコード参照を見るので、メソッドの最後まで収集されます。ただし、nullの設定を省略した場合、CLRは、コードの特定のポイントの後にオブジェクトの呼び出しがなくなったと判断し、メソッドがまだ完了していなくても、GCはオブジェクトを収集できます。

17
user1739635

Nullへの割り当ては、一般に悪い考えです。

  1. 概念的には、それは無意味です。
  2. 多くの変数を使用すると、メソッドのサイズをかなり大きくするほどのnullへの追加割り当てが発生する可能性があります。何かのソースコードが長いほど、それを読み取るために多くの精神的な努力が払われ(たとえその多くがフィルターで除外できるものであっても)、バグを特定するのが容易になります。コードをわかりやすくする場合にのみ、コードを必要以上に冗長にします。
  3. Null割り当てが最適化されない可能性があります。その場合、コンパイルされたコードは実際にそのnull割り当てに到達するまで実際の割り当て解除を行わない可能性がありますが、ほとんどの場合、変数がスコープから外れる(そして場合によってはその前に)以外は何も実行しません。割り当てを解除できます。したがって、パフォーマンスへの影響はごくわずかです。

Nullが実際に明示的に割り当てたい値であるのではなく、使用されなくなった変数を「クリア」するために何かをnullに割り当てるのは、次の2つのケースのいずれかです。

  1. これは、存続期間が長い可能性のあるオブジェクトのメンバーであり、そのオブジェクトによって使用されなくなり、かなりのサイズになります。ここでnullへの割り当ては最適化です。
  2. これは、存続期間が長い可能性のあるオブジェクトのメンバーであり、そのオブジェクトによって使用されなくなるため、そのリソースを解放するために破棄されました。ここでnullに割り当てることは安全上の問題です。廃棄されたオブジェクトを誤って使用するよりも、誤ってnullオブジェクトを使用する場合を見つけやすくなるためです。

これらのケースはどちらもローカル変数には適用されず、メンバーにのみ適用されます。両方ともまれです。

12
Jon Hanna

いいえ。ローカル変数に関しては、オブジェクトへの参照があるかどうかに関係なく、参照が使用されるかどうかが重要です。

コードにnullの割り当てを追加してもパフォーマンスに大きな影響はなく、メモリ管理にもまったく影響はありませんが、コードにやる気のないステートメントが追加され、読みにくくなります。

ガベージコレクターは、コード内で最後に参照がいつ使用されたかを認識しているため、不要になったオブジェクトをすぐに収集できます。

例:

{
  // Create an object
  StringBuilder b = new StringBuilder();
  b.Append("asdf");
  // Here is the last use of the object:
  string x = b.ToString();
  // From this point the object can be collected whenever the GC feels like it
  // If you assign a null reference to the variable here is irrelevant
  b = null;
}
5
Guffa

IDisposableを実装する必要があるオブジェクトの場合、慣例として、IDisposableの実装ですべてのメンバーをnullに設定します。

遠い昔、私はこの方法により、Windows Mobileで実行されている.NET Compact Frameworkアプリケーションのメモリ消費とパフォーマンスが大幅に向上することを発見しました。当時の.NET Compact Frameworkは、メインの.NET Frameworkと比較して、ガベージコレクターの実装が非常に最小限であったと思います。IDisposableの実装でオブジェクトを分離する動作は、.NET Compact FrameworkでのGCに役立ちました。

この方法のもう1つの理由は、IDisposableがオブジェクトで実行された後、破棄されたオブジェクトのメンバーを使用しようとすることは実際には望ましくないことです。理想的には、何かがその関数にアクセスしようとしたときに破棄されたオブジェクトからObjectDisposedExceptionを取得するのが理想的ですが、その代わりに、NullReferenceExceptionの方が例外がないよりはましです。解放されたアンマネージリソースをいじるのは、アプリケーションに多くの問題を引き起こす可能性があるため、破棄されたオブジェクトをいじるコードについて知りたい。

注:メンバーをnullに設定する以外に、オブジェクトにIDisposableを実装することは絶対に推奨しません。他の理由でIDisposableを実装する必要がある場合、つまり、IDisposableを実装するメンバーがあるか、オブジェクトがアンマネージリソースをラップする場合について話します。

0
Mick

AFAIKを追加したいのですが、これはVisual Basicの1ポイントリリースの有効なパターンにすぎず、 that でも多少議論の余地がありました。 (IIRCはDAOオブジェクト専用でした。)

0
Mark Hurd