Visual Studio の null 参照の警告 - エラーが表示されないのはなぜですか?
-
06-07-2019 - |
質問
Visual Studio に関して奇妙なことに気づきました。まず、関数のどこかにこれ (C#) を入力してみてください。
class Foo
{
public void Bar()
{
string s;
int i = s.Length;
}
}
さて、すぐにマークされます s
で s.Length
エラーとして、「Use of unassigned local variable 's'
」。一方、次のコードを試してください。
class Foo
{
private string s;
public void Bar()
{
int i = s.Length;
}
}
コンパイルされ、下線が引かれます s
で private string s
「」という警告とともにField 'Foo.s' is never assigned to, and will always have its default value null
".
さて、VS がそれほど賢く、 s が常に null であることを知っているのであれば、なぜ 2 番目の例でその長さを取得することがエラーにならないのでしょうか?私の当初の推測は、「コンパイラが単にジョブを完了できない場合にのみコンパイル エラーが発生する。コードは技術的には Bar() を呼び出さない限り実行されるため、これは単なる警告です。」 ただし、その説明は最初の例によって無効になります。Bar() を呼び出さない限り、エラーなしでコードを実行できます。それで何が与えられるのでしょうか?単なる見落とし、それとも何か見落としがあるのでしょうか?
解決
最初の例(エラー)は、コンパイラの definite-assignment トラッキング。これはローカル変数にのみ適用されます。コンテキストが限られているため、コンパイラはこの状況をしっかりと把握しています。 s
はnullではなく、未定義であることに注意してください。
2番目の例では、 s
はフィールドです(デフォルトはnullです)。コンパイラエラーはありませんが、実行時に常にキャッチされます。この特定のケースはトラップされる可能性がありますが、この種のエラーは一般にコンパイラーによって検出されません。
たとえば、文字列を s
に割り当てるメソッド Bar2()
を追加できますが、 Bar()
より後に呼び出すか、すべて。これにより、警告は削除されますが、実行時エラーは削除されません。
これは仕様によるものです。
他のヒント
2番目の例では、コードは有効ですが、正しく実行されない可能性があります。このプログラムが「正常に」実行できるいくつかのケースを以下に示します
- コンパイラは完全に正しいわけではありません。 「s」は可能です。インスタンスがリフレクションによって変更された場合、null以外の値を持つようにします。
- メソッドBarが呼び出されない場合、プログラムはエラーなしで実行できます
- このプログラムは、テスト上の理由でNullReferenceExceptionをトリガーするテストプログラムである可能性があります
私ができる唯一の推測は、2番目の例では、リフレクションによってsを変更できるということです(BindingFlags.Privateを使用してプライベートメンバーにアクセスします)。
最初のサンプルでは s はローカル変数であり、コンパイラはそれを簡単にチェックできます。 s 変数は使用前に割り当てられませんでした。
2 番目のものでは、 s はグローバル変数であり、クラス内の別の場所で初期化された可能性があります。