NullReferenceExceptionとは何ですか?どのように修正しますか?


1875

私はいくつかのコードを持っていて、それが実行されると、をスローして次のようNullReferenceExceptionに言います:

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

これはどういう意味ですか?このエラーを修正するにはどうすればよいですか?


- VS 2017での例外ヘルパーは、この例外の原因を診断する際に、より便利になりますblogs.msdn.microsoft.com/visualstudio/2016/11/28/...の下で新しい例外ヘルパーを
Zev Spitz、

今後の訪問者の皆様へ、この質問への回答はArgumentNullExceptionにも同様に適用されます。この質問の重複として質問がクローズされ、ANEが発生している場合は、回答の指示に従って問題をデバッグおよび修正してください。

@will ANEは、nullがパラメーターとして渡された場合にのみ発生します。ANEの質問がこの質問の複製としてクローズされた場合の例を挙げられますか?
John Saunders、

メタで出てきましたが、リンクを掘りに行かなくてはなりません。ただし、そのコメントに関しては、ANEは単なるNREですが、誰かがプリエンプティブチェックを追加し、少なくともnullが何であるか(引数名が提供されます)を正確に知っているため、まっすぐなNREよりも診断が少し簡単です。

回答:


2415

原因は何ですか?

ボトムライン

null(またはNothingVB.NETで)何かを使用しようとしています。つまり、に設定nullするか、まったく何も設定しません。

他のように、null周りに渡されます。それがある場合null には方法「A」、それはその方法であることができ、「B」は合格null メソッド「A」。

null 異なる意味を持つことができます:

    1. 初期化されていないために何もポイントしないオブジェクト変数この場合、そのようなオブジェクトのプロパティまたはメソッドにアクセスすると、が発生しNullReferenceExceptionます。
    1. 現像液は、使用してnull利用可能な意味のある値がないことを示すために意図的に。C#には変数のnull許容データ型の概念があることに注意してください(データベーステーブルはnull許容フィールドを持つことができるように)-変数に割り当てnullて、値が格納されていないことを示すことができます。たとえばint? a = null;、疑問符はnullの格納が許可されていることを示します変数aif (a.HasValue) {...}またはで確認できif (a==null) {...}ます。aこの例のようなnull可能変数は、a.Value明示的に、または通常どおりを介して、値にアクセスできますa
      経由でアクセスすることをa.Value投げるInvalidOperationException代わりのNullReferenceException場合aですnull-あなたは別のオンNULL可能変数を持っている場合、すなわち、事前チェックを行う必要がありint b;、あなたのような代入すればいいif (a.HasValue) { b = a.Value; }か短いをif (a != null) { b = a; }

この記事の残りの部分では、より詳細に説明し、多くのプログラマーがしばしば犯す間違いを示しますNullReferenceException

すなわち

runtime投げNullReferenceException いつもあなたがリファレンスを使用しようとしている、と参照が初期化されていない(またはそれがされた:同じことを意味し、一度初期化されているが、もはや初期化されません)。

つまり、参照はnullであり、null参照を通じてメンバー(メソッドなど)にアクセスすることはできません。最も単純なケース:

string foo = null;
foo.ToUpper();

を指す参照でNullReferenceExceptionインスタンスメソッドToUpper()を呼び出すことができないため、これは2行目にをスローstringnullます。

デバッグ中

どのようにしてソースを見つけますNullReferenceExceptionか?別にそれが発生した場所に正確にスローされます例外自体、見てから、Visual Studioでのデバッグの一般的なルールが適用されます。場所戦略的なブレークポイントとは、あなたの変数を検査し、いずれかの(開く、それらの名前の上にマウスを置くことにより、 Quick)Watchウィンドウ、またはLocalsやAutosなどのさまざまなデバッグパネルの使用。

参照が設定されている場所または設定されていない場所を確認するには、その名前を右クリックして[すべての参照を検索]を選択します。次に、見つかったすべての場所にブレークポイントを配置し、デバッガーを接続してプログラムを実行できます。デバッガーがこのようなブレークポイントでブレークするたびに、参照がnullでないと予想されるかどうかを判断し、変数を検査して、予想どおりにインスタンスを指すことを確認する必要があります。

この方法でプログラムフローを実行することにより、インスタンスをnullにしてはならない場所、およびインスタンスが正しく設定されていない理由を見つけることができます。

例外がスローされる可能性があるいくつかの一般的なシナリオ:

ジェネリック

ref1.ref2.ref3.member

ref1、ref2、またはref3がnullの場合、を取得しNullReferenceExceptionます。問題を解決したい場合は、式をより単純な同等のものに書き直して、どれがnullかを調べます。

var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member

特に、ではHttpContext.Current.User.Identity.NameHttpContext.Currentがnullであるか、Userプロパティがnullであるか、Identityプロパティがnullである可能性があります。

間接

public class Person 
{
    public int Age { get; set; }
}
public class Book 
{
    public Person Author { get; set; }
}
public class Example 
{
    public void Foo() 
    {
        Book b1 = new Book();
        int authorAge = b1.Author.Age; // You never initialized the Author property.
                                       // there is no Person to get an Age from.
    }
}

子(Person)のnull参照を回避したい場合は、親(Book)オブジェクトのコンストラクターで初期化できます。

ネストされたオブジェクト初期化子

同じことがネストされたオブジェクト初期化子にも当てはまります。

Book b1 = new Book 
{ 
   Author = { Age = 45 } 
};

これは

Book b1 = new Book();
b1.Author.Age = 45;

newキーワードが使用されている間は、の新しいインスタンスは作成されますがBook、の新しいインスタンスは作成されないPersonためAuthor、プロパティはのままnullです。

ネストされたコレクション初期化子

public class Person 
{
    public ICollection<Book> Books { get; set; }
}
public class Book 
{
    public string Title { get; set; }
}

ネストされたコレクションInitializersは同じように動作します。

Person p1 = new Person 
{
    Books = {
         new Book { Title = "Title1" },
         new Book { Title = "Title2" },
    }
};

これは

Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });

new Person唯一のインスタンスを作成しPersonますが、Booksコレクションはまだですnull。コレクションInitializer構文では、のコレクションは作成されません。ステートメントにp1.Books変換されるだけp1.Books.Add(...)です。

アレイ

int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.

配列要素

Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
                   // initialized. There is no Person to set the Age for.

ギザギザの配列

long[][] array = new long[1][];
array[0][0] = 3; // is null because only the first dimension is yet initialized.
                 // Use array[0] = new long[2]; first.

コレクション/リスト/辞書

Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
                               // There is no Dictionary to perform the lookup.

範囲変数(間接/据え置き)

public class Person 
{
    public string Name { get; set; }
}
var people = new List<Person>();
people.Add(null);
var names = from p in people select p.Name;
string firstName = names.First(); // Exception is thrown here, but actually occurs
                                  // on the line above.  "p" is null because the
                                  // first element we added to the list is null.

イベント

public class Demo
{
    public event EventHandler StateChanged;

    protected virtual void OnStateChanged(EventArgs e)
    {        
        StateChanged(this, e); // Exception is thrown here 
                               // if no event handlers have been attached
                               // to StateChanged event
    }
}

###Bad Naming Conventions:

If you named fields differently from locals, you might have realized that you never initialized the field. 

パブリッククラスForm1 {プライベートカスタマーカスタマー。

private void Form1_Load(object sender, EventArgs e) 
{
    Customer customer = new Customer();
    customer.Name = "John";
}

private void Button_Click(object sender, EventArgs e)
{
    MessageBox.Show(customer.Name);
}

}

これは、フィールドに下線を付けるための規則に従うことで解決できます。

    private Customer _customer;

ASP.NETページのライフサイクル:

public partial class Issues_Edit : System.Web.UI.Page
{
    protected TestIssue myIssue;

    protected void Page_Load(object sender, EventArgs e)
    {
        if (!IsPostBack)
        {
             // Only called on first load, not when button clicked
             myIssue = new TestIssue(); 
        }
    }

    protected void SaveButton_Click(object sender, EventArgs e)
    {
        myIssue.Entry = "NullReferenceException here!";
    }
}

ASP.NETセッション値

// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();

ASP.NET MVC空のビューモデル

プロパティ参照するときに例外が発生した場合@ModelではASP.NET MVC View、あなたがいることを理解する必要があるModelときに、あなたのアクションメソッドに設定されますreturnビュー。コントローラーから空のモデル(またはモデルプロパティ)を返すと、ビューがアクセスしたときに例外が発生します。

// Controller
public class Restaurant:Controller
{
    public ActionResult Search()
    {
        return View();  // Forgot the provide a Model here.
    }
}

// Razor view 
@foreach (var restaurantSearch in Model.RestaurantSearch)  // Throws.
{
}

<p>@Model.somePropertyName</p> <!-- Also throws -->

WPFコントロールの作成順序とイベント

WPFコントロールはInitializeComponent、ビジュアルツリーに表示される順序でへの呼び出し中に作成されます。A NullReferenceExceptionは、イベントハンドラーなどを使用して早期に作成されたコントロールの場合に発生します。イベントハンドラーなどは、その期間中InitializeComponentに作成され、後で作成されたコントロールを参照します。

例えば ​​:

<Grid>
    <!-- Combobox declared first -->
    <ComboBox Name="comboBox1" 
              Margin="10"
              SelectedIndex="0" 
              SelectionChanged="comboBox1_SelectionChanged">
       <ComboBoxItem Content="Item 1" />
       <ComboBoxItem Content="Item 2" />
       <ComboBoxItem Content="Item 3" />
    </ComboBox>

    <!-- Label declared later -->
    <Label Name="label1" 
           Content="Label"
           Margin="10" />
</Grid>

ここcomboBox1はの前に作成されlabel1ます。場合はcomboBox1_SelectionChanged、参照`LABEL1への試み、それがまだ作成されていません。

private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}

の宣言の順序を変更するとXAML(つまり、label1comboBox1にリストし、設計哲学の問題を無視すると)、少なくともNullReferenceExceptionここで解決されます。

キャスト as

var myThing = someObject as Thing;

これはスローしませんInvalidCastExceptionnull、キャストが失敗した場合(およびsomeObjectそれ自体がnullの場合)を返します。ですので注意してください。

LINQ FirstOrDefault()SingleOrDefault()

プレーンバージョンでは、何もないときに例外First()Single()スローします。その場合、「OrDefault」バージョンはnullを返します。ですので注意してください。

foreach

foreachnullコレクションを反復しようとするとスローされます。通常、nullコレクションを返すメソッドからの予期しない結果が原因です。

List<int> list = null;    
foreach(var v in list) { } // exception

より現実的な例-XMLドキュメントからノードを選択します。ノードが見つからない場合にスローされますが、初期デバッグではすべてのプロパティが有効であることが示されます。

foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))

回避する方法

nullnull値を明示的にチェックして無視します。

参照がnullになることが予想される場合は、nullインスタンスメンバーにアクセスする前に参照があるかどうかを確認できます。

void PrintName(Person p)
{
    if (p != null) 
    {
        Console.WriteLine(p.Name);
    }
}

nullデフォルト値を明示的に確認して提供します。

nullたとえば、探しているオブジェクトが見つからない場合など、インスタンスを返すと予想されるメソッド呼び出しはを返すことができます。この場合、デフォルト値を返すように選択できます。

string GetCategory(Book b) 
{
    if (b == null)
        return "Unknown";
    return b.Category;
}

nullfromメソッド呼び出しを明示的にチェックし、カスタム例外をスローします。

カスタム例外をスローして、呼び出し元のコードでキャッチすることもできます。

string GetCategory(string bookTitle) 
{
    var book = library.FindBook(bookTitle);  // This may return null
    if (book == null)
        throw new BookNotFoundException(bookTitle);  // Your custom exception
    return book.Category;
}

使用するDebug.Assert値はなることはありません場合はnull、以前の例外が発生するよりも、問題をキャッチするために、。

開発中にメソッドが復帰nullする可能性があるが復帰すべきでないことがわかっている場合は、を使用Debug.Assert()して、発生したときにできるだけ早くブレークすることができます。

string GetTitle(int knownBookID) 
{
    // You know this should never return null.
    var book = library.GetBook(knownBookID);  

    // Exception will occur on the next line instead of at the end of this method.
    Debug.Assert(book != null, "Library didn't return a book for known book ID.");

    // Some other code

    return book.Title; // Will never throw NullReferenceException in Debug mode.
}

このチェックはリリースビルド終了しないため、リリースモードでの実行時にNullReferenceException再度スローbook == nullされます。

使用GetValueOrDefault()のためにnullable、彼らがあるときに、デフォルト値を提供するために、値型null

DateTime? appointment = null;
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the default value provided (DateTime.Now), because appointment is null.

appointment = new DateTime(2022, 10, 20);
Console.WriteLine(appointment.GetValueOrDefault(DateTime.Now));
// Will display the appointment date, not the default

ヌル合体演算子??[C#]またはIf()[VB]を使用します。

nullが発生したときにデフォルト値を提供するための省略表現:

IService CreateService(ILogger log, Int32? frobPowerLevel)
{
   var serviceImpl = new MyService(log ?? NullLog.Instance);

   // Note that the above "GetValueOrDefault()" can also be rewritten to use
   // the coalesce operator:
   serviceImpl.FrobPowerLevel = frobPowerLevel ?? 5;
}

null条件演算子を使用:?.または?[x]配列(C#6およびVB.NET 14で使用可能):

これは、セーフナビゲーションまたはElvis(その形状の後)オペレーターとも呼ばれます。演算子の左側の式がnullの場合、右側は評価されず、代わりにnullが返されます。つまり、次のような場合です。

var title = person.Title.ToUpper();

人物にタイトルがない場合はToUpper、null値のプロパティを呼び出そうとしているため、例外がスローされます。

C# 5、以下、これをでガードすることができます。

var title = person.Title == null ? null : person.Title.ToUpper();

これで、タイトル変数は例外をスローする代わりにnullになります。C#6では、このための短い構文が導入されています。

var title = person.Title?.ToUpper();

これは、タイトルの変数であることになりnull、通話がしToUpperた場合に行われていないperson.Titleですnull

もちろん、あなたはまだチェックする必要がtitleヌルまたは(ヌル合体演算子と一緒にヌル条件演算子を使用する??デフォルト値を指定します):

// regular null check
int titleLength = 0;
if (title != null)
    titleLength = title.Length; // If title is null, this would throw NullReferenceException

// combining the `?` and the `??` operator
int titleLength = title?.Length ?? 0;

同様に、配列の場合は?[i]次のように使用できます。

int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");

これは次のことを行います。myIntArrayがnullの場合、式はnullを返し、安全に確認できます。配列が含まれている場合は、以下と同じように処理し elem = myIntArray[i];i<sup>th</sup>要素を返します。

nullコンテキストを使用(C#8で利用可能):

C# 8そこに導入されたnullコンテキストとnullable参照型は、変数の静的分析を実行し、値が潜在的にnullである可能性がある場合、またはnullに設定されている場合にコンパイラ警告を提供します。null可能な参照型により、型を明示的にnullにすることができます。

null可能な注釈コンテキストとnull可能な警告コンテキストはNullablecsprojファイル内の要素を使用してプロジェクトに設定できます。この要素は、コンパイラーが型のNULL可能性を解釈する方法と生成される警告を構成します。有効な設定は次のとおりです。

  • enable:null可能な注釈コンテキストが有効になります。null許容の警告コンテキストが有効になります。参照型の変数(文字列など)はnullにできません。ヌル可能性の警告はすべて有効になっています。
  • disable:null可能なアノテーションコンテキストが無効になります。null許容の警告コンテキストは無効になっています。参照型の変数は、以前のバージョンのC#と同様に気づかれません。NULL可能性の警告はすべて無効になります。
  • safeonly:null可能なアノテーションコンテキストが有効になります。null許容の警告コンテキストはsafeonlyです。参照型の変数はnullにできません。すべての安全ヌル可能性警告が有効になっています。
  • 警告:nullableアノテーションコンテキストは無効です。null許容の警告コンテキストが有効になります。参照型の変数は気付かない。ヌル可能性の警告はすべて有効になっています。
  • safeonlywarnings:null許容の注釈コンテキストは無効です。null許容の警告コンテキストはsafeonlyです。参照型の変数は気付かない。すべての安全ヌル可能性警告が有効になっています。

null可能な参照型は、null可能な値型と同じ構文を使用して示され?ます。変数の型にa が追加されます。

イテレータのnull参照をデバッグおよび修正するための特別なテクニック

C#「イテレータブロック」(他の一部の一般的な言語では「ジェネレータ」と呼ばれます)をサポートしています。実行の遅延のため、null逆参照例外は反復子ブロックでデバッグするのが特に難しい場合があります。

public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
    for (int i = 0; i < count; ++i)
    yield return f.MakeFrob();
}
...
FrobFactory factory = whatever;
IEnumerable<Frobs> frobs = GetFrobs();
...
foreach(Frob frob in frobs) { ... }

場合whateverでの結果null、その後はMakeFrobスローされます。さて、あなたは正しいことはこれだと思うかもしれません:

// DON'T DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   if (f == null) 
      throw new ArgumentNullException("f", "factory must not be null");
   for (int i = 0; i < count; ++i)
      yield return f.MakeFrob();
}

なぜこれが間違っているのですか?反復子ブロックは、実際にはありませんので、実行までforeach!への呼び出しGetFrobsは、反復されると反復子ブロックを実行するオブジェクトを返すだけです。

このようにnullチェックを作成すると、null逆参照を防止できますが、null引数の例外を反復のポイントに移動します呼び出しのポイントではなくデバッグ非常に混乱します。

正しい修正は次のとおりです。

// DO THIS
public IEnumerable<Frob> GetFrobs(FrobFactory f, int count)
{
   // No yields in a public method that throws!
   if (f == null) 
       throw new ArgumentNullException("f", "factory must not be null");
   return GetFrobsForReal(f, count);
}
private IEnumerable<Frob> GetFrobsForReal(FrobFactory f, int count)
{
   // Yields in a private method
   Debug.Assert(f != null);
   for (int i = 0; i < count; ++i)
        yield return f.MakeFrob();
}

つまり、イテレーターブロックロジックを持つプライベートヘルパーメソッドと、nullチェックを実行してイテレーターを返すパブリックサーフェスメソッドを作成します。今はGetFrobsに呼び出され、nullのチェックはすぐに起こり、その後、GetFrobsForRealシーケンスが繰り返されるときに実行されます。

参照ソースを調べる場合 LINQオブジェクトのこの手法が全体で使用されていることがわかります。書くのは少し不格好ですが、ヌルエラーのデバッグがはるかに簡単になります。 作成者の便宜ではなく、呼び出し元の便宜のためにコードを最適化します

安全でないコードでのnull逆参照に関する注意

C#メモリの安全性と型の安全性を提供する通常の安全メカニズムが強制されないため、名前が示すように、非常に危険な「安全でない」モードがあります。メモリがどのように機能するかを十分に理解していない限り、安全でないコードを書くべきではありません。

安全でないモードでは、2つの重要な事実に注意する必要があります。

  • null ポインターの逆参照は、null 参照の逆参照と同じ例外を生成します
  • 無効なnull以外のポインタを逆参照すると、状況によってはその例外発生する可能性があります

その理由を理解するには、最初に.NETがnull逆参照例外を生成する方法を理解することが役立ちます。(これらの詳細は、Windowsで実行されている.NETに適用されます。他のオペレーティングシステムも同様のメカニズムを使用します。)

メモリはで仮想化されWindowsます。各プロセスは、オペレーティングシステムによって追跡されるメモリの多くの「ページ」の仮想メモリ空​​間を取得します。メモリの各ページには、読み取り、書き込み、実行など、使用方法を決定するフラグが設定されています。最低ページは、「今までにどのような方法で使用される場合、エラーを生成」としてマークされています。

のnullポインターとnull参照はどちらC#も内部的にはゼロとして表されるため、対応するメモリストレージに逆参照しようとすると、オペレーティングシステムでエラーが発生します。次に.NETランタイムはこのエラーを検出し、それをnull逆参照例外に変換します。

そのため、nullポインターとnull参照の両方を逆参照すると、同じ例外が発生します。

2番目のポイントはどうですか?いずれかの逆参照仮想メモリの最下位ページにある無効なポインタをと、同じオペレーティングシステムエラーが発生し、同じ例外が発生します。

これはなぜ意味があるのですか?2つの整数を含む構造体と、nullに等しいアンマネージポインターがあるとします。構造体の2番目のintを逆参照CLRしようとした場合、は場所0のストレージにアクセスしようとしません。ロケーション4のストレージにアクセスします。しかし、論理的にはnull 経由でそのアドレスに到達するため、これはnull逆参照です。

安全でないコードを使用していて、null逆参照例外が発生した場合は、問題のポインタをnullにする必要がないことに注意してください。最下部のページの任意の場所にすることができ、この例外が生成されます。


55
多分これはばかげたコメントかもしれませんが、この問題を回避するための最初で最良の方法はオブジェクトを初期化することではないでしょうか?私にとってこのエラーが発生するのは、通常、配列要素のようなものを初期化するのを忘れたためです。オブジェクトをnullとして定義してから参照することは、あまり一般的ではないと思います。多分説明に隣接する各問題を解決する方法を与えます。まだ良い投稿です。
JPK、2014年

30
オブジェクトがなく、メソッドまたはプロパティからの戻り値がある場合はどうなりますか?
John Saunders、

6
本/著者の例は少し奇妙です...それはどのようにコンパイルされますか?インテリセンスはどのように機能しますか?これは何ですか私は

5
@Will:最後の編集は役に立ちますか?そうでない場合は、問題と見なす内容をより明確にしてください。
ジョンサンダース

6
@JohnSaundersああ、いや、ごめんなさい、私はそのオブジェクト初期化バージョンを意味していました。 new Book { Author = { Age = 45 } };内部の初期化はどのように行われますか?内部のinitが機能する状況は考えられませんが、コンパイルされてインテリセンスが機能します...構造体を除いては?

311

NullReference例外— Visual Basic

NullReference Exception以下のためにのVisual Basicは、 1つの違いはありませんC# 。結局のところ、どちらも.NET Frameworkで定義されている同じ例外を報告しており、どちらも使用しています。Visual Basicに固有の原因はまれです(おそらく1つだけ)。

この回答では、Visual Basicの用語、構文、およびコンテキストを使用します。使用されている例は、過去のスタックオーバーフローに関する多数の質問に基づいています。これは、種類を使用して関連性を最大化することですが多いの記事で見られる状況を。それを必要とするかもしれない人々のために、もう少し説明が提供されます。あなたに似た例がされて非常に可能性がここに記載されています。

注意:

  1. これは概念ベースです。プロジェクトに貼り付けるコードはありません。これは、NullReferenceException(NRE)の原因、それを見つける方法、それを修正する方法、およびそれを回避する方法を理解するのに役立つことを目的としています。NREはさまざまな原因で発生する可能性があるため、これが唯一の遭遇であるとは考えられません。
  2. (スタックオーバーフローの投稿からの)例は、常に最初から何かを行うための最良の方法を常に示しているわけではありません。
  3. 通常、最も簡単な対策が使用されます。

基本的な意味

「オブジェクトがオブジェクトのインスタンスに設定されていません」というメッセージは、初期化されていないオブジェクトを使用しようとしていることを意味します。これは、次のいずれかに要約されます。

  • コードオブジェクト変数を宣言しましたが、それを初期化しませんでした(インスタンスを作成するか、 ' インスタンス化しますてください)
  • あなたのコードがオブジェクトを初期化すると仮定した何かはしませんでした
  • おそらく、他のコードがまだ使用中のオブジェクトを時期尚早に無効にしました

原因を見つける

問題はであるオブジェクト参照なので、Nothing答えはそれらを調べてどれを見つけるかです。次に、初期化されていない理由を判別します。さまざまな変数の上にマウスを置くと、Visual Studio(VS)にそれらの値が表示されます-原因は次のとおりNothingです。

IDEデバッグ表示

また、関連するコード、特にCatchブロックに何もないものから、Try / Catchブロックを削除する必要もあります。これにより、であるオブジェクトを使用しようとすると、コードがクラッシュしますNothingこれは、問題の正確な場所を特定し、問題の原因となっているオブジェクトを特定できるためです。

MsgBox表示Error while...されるキャッチのA はほとんど役に立ちません。この方法も非常に悪いは、実際の例外、関係するオブジェクト、またはそれが発生するコード行さえ記述できないため、スタックオーバーフローの質問ます。

Locals WindowDebug-> Windows-> Locals)を使用してオブジェクトを調べることもできます。

問題がどこにあるかがわかったら、通常は修正がかなり簡単で、新しい質問を投稿するよりも速くなります。

以下も参照してください。

例と対策

クラスオブジェクト/インスタンスの作成

Dim reg As CashRegister
...
TextBox1.Text = reg.Amount         ' NRE

問題はDim、CashRegister オブジェクトを作成しないことです。regそのタイプの名前が付けられた変数を宣言するだけです。オブジェクト変数の宣言インスタンスの作成は、2つの異なるものです。

療法

New多くの場合、オペレーターはインスタンスを宣言するときにインスタンスを作成するために使用できます。

Dim reg As New CashRegister        ' [New] creates instance, invokes the constructor

' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister

後でインスタンスを作成することが適切な場合:

Private reg As CashRegister         ' Declare
  ...
reg = New CashRegister()            ' Create instance

注:コンストラクター()を含め、プロシージャで再度使用しないでくださいDimSub New

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

これにより、そのコンテキスト(サブ)にのみ存在するローカル変数が作成regされます。他の場所で使用するregモジュールレベルの変数はScope残りNothingます。

New演算子がないことは、NullReference Exceptionsレビューされたスタックオーバーフローの質問見られる最大の。

Visual Basicは、次のように繰り返し使用してプロセスを明確にしようとします。オペレーターをNew使用Newすると、新しいオブジェクトが作成されSub New、コンストラクターが呼び出されます。ここで、オブジェクトは他の初期化を実行できます。

明確にするために、Dim(またはPrivate)は変数とそのを宣言するだけTypeです。変数のスコープ -変数がモジュール/クラス全体に存在するか、プロシージャのローカルであるかは、宣言された場所によって決まります。ScopePrivate | Friend | Publicではなく、アクセスレベルを定義します。

詳細については、以下を参照してください。


配列

配列もインスタンス化する必要があります。

Private arr as String()

この配列は宣言されただけで、作成されていません。配列を初期化する方法はいくつかあります。

Private arr as String() = New String(10){}
' or
Private arr() As String = New String(10){}

' For a local array (in a procedure) and using 'Option Infer':
Dim arr = New String(10) {}

注:VS 2010以降、リテラルとを使用してローカル配列を初期化する場合Option InferAs <Type>およびNew要素はオプションです。

Dim myDbl As Double() = {1.5, 2, 9.9, 18, 3.14}
Dim myDbl = New Double() {1.5, 2, 9.9, 18, 3.14}
Dim myDbl() = {1.5, 2, 9.9, 18, 3.14}

データのタイプと配列のサイズは、割り当てられているデータから推測されます。クラス/モジュールレベルの宣言にはAs <Type>Option Strict次のものが必要です。

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

例:クラスオブジェクトの配列

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

配列は作成されましたが、その中のFooオブジェクトは作成されていません。

療法

For i As Integer = 0 To arrFoo.Count - 1
    arrFoo(i) = New Foo()         ' Create Foo instance
    arrFoo(i).Bar = i * 10
Next

a List(Of T)を使用すると、有効なオブジェクトがない要素を作成することが非常に難しくなります。

Dim FooList As New List(Of Foo)     ' List created, but it is empty
Dim f As Foo                        ' Temporary variable for the loop

For i As Integer = 0 To 5
    f = New Foo()                    ' Foo instance created
    f.Bar =  i * 10
    FooList.Add(f)                   ' Foo object added to list
Next

詳細については、以下を参照してください。


リストとコレクション

.NETコレクション(リスト、辞書など、さまざまな種類があります)もインスタンス化または作成する必要があります。

Private myList As List(Of String)
..
myList.Add("ziggy")           ' NullReference

同じ理由で同じ例外が発生します- myList宣言されただけで、インスタンスは作成されませんでした。救済策は同じです:

myList = New List(Of String)

' Or create an instance when declared:
Private myList As New List(Of String)

一般的な見落としは、コレクションを使用するクラスですType

Public Class Foo
    Private barList As List(Of Bar)

    Friend Function BarCount As Integer
        Return barList.Count
    End Function

    Friend Sub AddItem(newBar As Bar)
        If barList.Contains(newBar) = False Then
            barList.Add(newBar)
        End If
    End Function

barListが宣言されているだけでインスタンス化されていないため、どちらの手順でもNRE が生成されます。のインスタンスを作成してFooも、内部のインスタンスは作成されませんbarList。コンストラクタでこれを行う意図があったかもしれません:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

前と同じように、これは正しくありません。

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

詳細については、「List(Of T)クラス」を参照してください。


データプロバイダーオブジェクト

多くのオブジェクトが存在する可能性があるため、データベースのプレゼントでNullReferenceための多くの機会を操作(CommandConnectionTransactionDatasetDataTableDataRows....)一度使用中。 注:これは、どのデータプロバイダを使用している問題ではない-のMySQL、SQL Serverの、のOleDB、など- のコンセプトを。は同じです。

例1

Dim da As OleDbDataAdapter
Dim ds As DataSet
Dim MaxRows As Integer

con.Open()
Dim sql = "SELECT * FROM tblfoobar_List"
da = New OleDbDataAdapter(sql, con)
da.Fill(ds, "foobar")
con.Close()

MaxRows = ds.Tables("foobar").Rows.Count      ' Error

以前と同様に、dsDatasetオブジェクトが宣言されましたが、インスタンスは作成されませんでした。DataAdapter既存記入しますDataSet、1を作成していません。この場合、dsはローカル変数なので、IDEはこれが発生する可能性があること警告します

img

モジュール/クラスレベル変数として宣言された場合、の場合のようconに、コンパイラはオブジェクトが上流のプロシージャによって作成されたかどうかを知ることができません。警告を無視しないでください。

療法

Dim ds As New DataSet

例2

ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")

txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)

ここでのタイプミスは問題です:Employeesvs Employee。何があったDataTableので、「従業員」という名前の作成しないNullReferenceException結果がそれにアクセスしようとしています。別の潜在的な問題はItems、SQLにWHERE句が含まれている場合にそうでない可能性があると想定することです。

療法

これは1つのテーブルを使用Tables(0)するため、を使用するとスペルミスを回避できます。調べるRows.Countことも役立ちます:

If ds.Tables(0).Rows.Count > 0 Then
    txtID.Text = ds.Tables(0).Rows(0).Item(1)
    txtID.Name = ds.Tables(0).Rows(0).Item(2)
End If

FillRows影響を受ける数も返す関数で、これもテストできます。

If da.Fill(ds, "Employees") > 0 Then...

例3

Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
        TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
        FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)

If ds.Tables("TICKET_RESERVATION").Rows.Count > 0 Then

DataAdapter提供されるTableNames前の例で示したように、それは、SQLまたはデータベーステーブルから解析名をしません。結果として、ds.Tables("TICKET_RESERVATION")存在しないテーブルを参照します。

対処方法インデックスでテーブルを参照し、同じです。

If ds.Tables(0).Rows.Count > 0 Then

DataTableクラスも参照してください。


オブジェクトパス/ネスト

If myFoo.Bar.Items IsNot Nothing Then
   ...

コードはItems両方myFooをテストしているだけBarで、何もない場合もあります。救済策は一度に全体鎖またはオブジェクト一方のパスをテストすることです。

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

AndAlsoは重要。最初のFalse条件が発生すると、その後のテストは実行されません。これにより、コードは一度に1レベルずつオブジェクトに安全に「ドリル」でき、有効であると判断されたmyFoo.Bar場合にのみ評価myFooされます。複雑なオブジェクトをコーディングすると、オブジェクトチェーンまたはパスが非常に長くなることがあります。

myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")

nullオブジェクトの「下流」を参照することはできません。これはコントロールにも適用されます。

myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"

ここでは、myWebBrowserまたはDocumentNothingであるか、formfld1要素が存在しない可能性があります。


UIコントロール

Dim cmd5 As New SqlCommand("select Cartons, Pieces, Foobar " _
     & "FROM Invoice where invoice_no = '" & _
     Me.ComboBox5.SelectedItem.ToString.Trim & "' And category = '" & _
     Me.ListBox1.SelectedItem.ToString.Trim & "' And item_name = '" & _
     Me.ComboBox2.SelectedValue.ToString.Trim & "' And expiry_date = '" & _
     Me.expiry.Text & "'", con)

特に、このコードは、ユーザーが1つ以上のUIコントロールで何かを選択していない可能性があることを予期していません。 ListBox1.SelectedItem可能性がありますNothingのでListBox1.SelectedItem.ToString、NREになります。

療法

データを使用する前に検証します(Option StrictSQLパラメータも使用します):

Dim expiry As DateTime         ' for text date validation
If (ComboBox5.SelectedItems.Count > 0) AndAlso
    (ListBox1.SelectedItems.Count > 0) AndAlso
    (ComboBox2.SelectedItems.Count > 0) AndAlso
    (DateTime.TryParse(expiry.Text, expiry) Then

    '... do stuff
Else
    MessageBox.Show(...error message...)
End If

別の方法として、 (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Visual Basicフォーム

Public Class Form1

    Private NameBoxes = New TextBox(5) {Controls("TextBox1"), _
                   Controls("TextBox2"), Controls("TextBox3"), _
                   Controls("TextBox4"), Controls("TextBox5"), _
                   Controls("TextBox6")}

    ' same thing in a different format:
    Private boxList As New List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}

    ' Immediate NRE:
    Private somevar As String = Me.Controls("TextBox1").Text

これは、NREを取得するためのかなり一般的な方法です。C#では、コーディング方法に応じて、IDEはControls現在のコンテキストに存在しない、または「非静的メンバーを参照できない」ことを報告します。したがって、ある程度、これはVBのみの状況です。また、障害のカスケードが発生する可能性があるため、複雑です。

配列とコレクションは、この方法では初期化できません。この初期化コードは、コンストラクターがまたはを作成するに実行されます。結果として:FormControls

  • リストとコレクションは単に空になります
  • 配列にはNothingの5つの要素が含まれます
  • somevar何も持っていないため、割り当てはすぐにNREになります.Textプロパティを

後で配列要素を参照すると、NREになります。でこれを行うForm_Loadと、奇妙なバグのため、IDE 例外が発生したときに例外を報告しない場合があります。コードが配列を使用しようとすると、例外が後でポップアップします。この「サイレント例外」については、この投稿で詳しく説明しています。私たちの目的にとって重要なのは、フォーム(Sub NewまたはForm Loadイベント)の作成中に致命的な事態が発生した場合、例外が報告されず、コードがプロシージャを終了してフォームを表示することです。

Sub NewまたはForm Loadイベント内の他のコードはNREの後に実行されないため、他の多くのものを初期化せずに残すことができます。

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

これは、すべてのコントロールおよびコンポーネントの参照に適用され、これらが以下の場所で違法になることに注意してください

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

部分的な救済

VBが警告を出さないのは不思議ですが、解決策はフォームレベルでコンテナーを宣言することですが、コントロール存在する場合はフォームロードイベントハンドラーでそれらを初期化ます。これはSub New、コードがInitializeComponent呼び出しの後にある限り実行できます。

' Module level declaration
Private NameBoxes as TextBox()
Private studentName As String

' Form Load, Form Shown or Sub New:
'
' Using the OP's approach (illegal using OPTION STRICT)
NameBoxes = New TextBox() {Me.Controls("TextBox1"), Me.Controls("TestBox2"), ...)
studentName = TextBox32.Text           ' For simple control references

配列コードはまだ森から出ていないかもしれません。コンテナコントロール内にあるコントロール(GroupBoxまたはPanel)は、では見つかりませんMe.Controls。それらは、そのPanelまたはGroupBoxのControlsコレクションに含まれます。また、コントロール名のスペルが間違っている場合もコントロールは返されません("TeStBox2")。そのような場合、Nothingは再びこれらの配列要素に格納され、NREを参照しようとすると結果が生成されます。

これらはあなたが探しているものを知っているので簡単に見つけられるはずです: VSはあなたの方法のエラーを示しています

「Button2」は Panel

療法

フォームのControlsコレクションを使用した名前による間接参照ではなく、コントロール参照を使用します。

' Declaration
Private NameBoxes As TextBox()

' Initialization -  simple and easy to read, hard to botch:
NameBoxes = New TextBox() {TextBox1, TextBox2, ...)

' Initialize a List
NamesList = New List(Of TextBox)({TextBox1, TextBox2, TextBox3...})
' or
NamesList = New List(Of TextBox)
NamesList.AddRange({TextBox1, TextBox2, TextBox3...})

何も返さない関数

Private bars As New List(Of Bars)        ' Declared and created

Public Function BarList() As List(Of Bars)
    bars.Clear
    If someCondition Then
        For n As Integer = 0 to someValue
            bars.Add(GetBar(n))
        Next n
    Else
        Exit Function
    End If

    Return bars
End Function

これは、IDEが「すべてのパスが値を返すわけではなく、NullReferenceException結果が生じる可能性がある」ことを警告する場合です。あなたは交換することにより、警告を抑制することができExit FunctionReturn Nothing、それは問題を解決していません。returnを使用しようとするsomeCondition = Falseと、NREになります。

bList = myFoo.BarList()
For Each b As Bar in bList      ' EXCEPTION
      ...

療法

Exit Function関数のをに置き換えReturn bListます。空を 返すことは、返すListことと同じではありませんNothing。返されたオブジェクトがになる可能性がある場合は、Nothing使用する前にテストしてください。

 bList = myFoo.BarList()
 If bList IsNot Nothing Then...

実装が不十分なTry / Catch

不適切に実装されたTry / Catchは、問題の場所を隠し、新しい問題を引き起こす可能性があります。

Dim dr As SqlDataReader
Try
    Dim lnk As LinkButton = TryCast(sender, LinkButton)
    Dim gr As GridViewRow = DirectCast(lnk.NamingContainer, GridViewRow)
    Dim eid As String = GridView1.DataKeys(gr.RowIndex).Value.ToString()
    ViewState("username") = eid
    sqlQry = "select FirstName, Surname, DepartmentName, ExtensionName, jobTitle,
             Pager, mailaddress, from employees1 where username='" & eid & "'"
    If connection.State <> ConnectionState.Open Then
        connection.Open()
    End If
    command = New SqlCommand(sqlQry, connection)

    'More code fooing and barring

    dr = command.ExecuteReader()
    If dr.Read() Then
        lblFirstName.Text = Convert.ToString(dr("FirstName"))
        ...
    End If
    mpe.Show()
Catch

Finally
    command.Dispose()
    dr.Close()             ' <-- NRE
    connection.Close()
End Try

これは、オブジェクトが期待どおりに作成されない場合ですが、emptyのカウンターの有用性も示していますCatch

SQLの余分なコンマ( 'mailaddress'の後)があり、で例外が発生し.ExecuteReaderます。後はCatch何もしない、Finallyクリーンアップを実行しようとしますが、あなたがすることができないのでClose、ヌルDataReaderオブジェクト、ブランドの新しいNullReferenceException結果。

空のCatchブロックは悪魔の遊び場です。このOPは、FinallyブロックでNREを取得する理由に困惑しました。他の状況では、空Catchが原因で下流に何か別の問題が発生し、問題の間違った場所で間違ったものを探すことに時間を費やすことになります。(上記の「サイレント例外」は同じ娯楽価値を提供します。)

療法

空のTry / Catchブロックを使用しないでください。コードをクラッシュさせて、a)原因を特定し、b)場所を特定し、c)適切な対策を適用します。Try / Catchブロックは、例外を修正するための一意の資格を持つ人(開発者)から例外を隠すことを目的としていません。


DBNullはNothingと同じではありません

For Each row As DataGridViewRow In dgvPlanning.Rows
    If Not IsDBNull(row.Cells(0).Value) Then
        ...

IsDBNull場合、この関数は、テストに使用されている値が等しいSystem.DBNullMSDNから:

System.DBNull値は、オブジェクトが欠落または存在しないデータを表すことを示します。DBNullは、変数がまだ初期化されていないことを示すNothingと同じではありません。

療法

If row.Cells(0) IsNot Nothing Then ...

前と同じように、Nothingをテストしてから、特定の値をテストできます。

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

例2

Dim getFoo = (From f In dbContext.FooBars
               Where f.something = something
               Select f).FirstOrDefault

If Not IsDBNull(getFoo) Then
    If IsDBNull(getFoo.user_id) Then
        txtFirst.Text = getFoo.first_name
    Else
       ...

FirstOrDefault最初の項目またはデフォルト値を返します。これはNothing参照タイプ用であり、決してDBNull次のことは行いません。

If getFoo IsNot Nothing Then...

コントロール

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

場合CheckBoxchkName見つからない(または内に存在するGroupBox)、次にchk何もなり、例外が発生する任意のプロパティを参照しようとします。

療法

If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...

DataGridView

DGVには定期的に見られるいくつかの癖があります。

dgvBooks.DataSource = loan.Books
dgvBooks.Columns("ISBN").Visible = True       ' NullReferenceException
dgvBooks.Columns("Title").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Author").DefaultCellStyle.Format = "C"
dgvBooks.Columns("Price").DefaultCellStyle.Format = "C"

場合dgvBooksがあるAutoGenerateColumns = True、それは名前によってそれらを参照するときに、上記のコードが失敗し、それが列を作成しますが、それは彼らを指していません。

療法

列に手動で名前を付けるか、インデックスで参照します。

dgvBooks.Columns(0).Visible = True

例2 — NewRowに注意してください

xlWorkSheet = xlWorkBook.Sheets("sheet1")

For i = 0 To myDGV.RowCount - 1
    For j = 0 To myDGV.ColumnCount - 1
        For k As Integer = 1 To myDGV.Columns.Count
            xlWorkSheet.Cells(1, k) = myDGV.Columns(k - 1).HeaderText
            xlWorkSheet.Cells(i + 2, j + 1) = myDGV(j, i).Value.ToString()
        Next
    Next
Next

あなたがする場合DataGridViewがあるAllowUserToAddRowsTrue(デフォルト)、Cells下部の空白で/新しい行がすべて含まれていますNothing。コンテンツ(などToString)を使用しようとすると、ほとんどの場合NREが発生します。

療法

For/Eachループを使用してIsNewRowプロパティをテストし、最後の行かどうかを確認します。これAllowUserToAddRowsは、true かどうかにかかわらず機能します。

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

あなたが使用する場合はFor nループを、行数または使用を変更するExit For際にIsNewRow当てはまります。


My.Settings(StringCollection)

特定の状況下で、であるアイテムを使用しようとすると、初めて使用したときにNullReferenceが発生My.SettingsするStringCollection可能性があります。解決策は同じですが、それほど明白ではありません。考慮してください:

My.Settings.FooBars.Add("ziggy")         ' foobars is a string collection

VBが設定を管理しているため、コレクションの初期化が期待されます。ただし、以前にコレクションに初期エントリを追加している場合に限ります(設定エディター内)。コレクションは(見かけ上)項目が追加されるときに初期化されるためNothing、設定エディターに追加する項目がない場合でもコレクションは残ります。

療法

Load必要に応じて、フォームのイベントハンドラーで設定コレクションを初期化します。

If My.Settings.FooBars Is Nothing Then
    My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If

通常、Settingsコレクションを初期化する必要があるのは、アプリケーションを初めて実行するときだけです。別の方法は、プロジェクト->設定|でコレクションに初期値を追加することですFooBars、プロジェクトを保存してから、偽の値を削除します。


キーポイント

あなたはおそらくNewオペレーターを忘れました。

または

あなたがコードに初期化されたオブジェクトを返すためにあなたがコードを完璧に実行するだろうとあなたが思った何かはしませんでした。

コンパイラの警告を無視せずOption Strict On(常に)、常に使用します。


MSDN NullReference例外


226

別のシナリオは、nullオブジェクトを値型にキャストする場合です。たとえば、次のコード:

object o = null;
DateTime d = (DateTime)o;

これは、スローされますNullReferenceExceptionキャストに。上記のサンプルではそれは明らかなようですが、これは、所有していないコードからnullオブジェクトが返され、キャストがたとえば自動システムによって生成された、「遅延バインディング」の複雑なシナリオで発生する可能性があります。

この1つの例は、Calendarコントロールを含む次の単純なASP.NETバインディングフラグメントです。

<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />

ここでSelectedDateは、実際にDateTimeは、CalendarWebコントロールタイプのプロパティ(タイプ)であり、バインディングは何かnullを完全に返す可能性があります。暗黙のASP.NETジェネレーターは、上記のキャストコードと同等のコードを作成します。そして、これはNullReferenceExceptionうまくコンパイルするASP.NET生成コードにあるため、見つけるのが非常に難しいを発生させます...


7
グレートキャッチ。回避するためのワンライナーの方法:DateTime x = (DateTime) o as DateTime? ?? defaultValue;
セルジュシュルツ2015年

160

これは、問題の変数が何も指されていないことを意味します。私はこれを次のように生成できます:

SqlConnection connection = null;
connection.Open();

変数 " connection"を宣言しましたが、何もポイントしていないため、エラーが発生します。メンバー " Open" を呼び出そうとすると、解決するための参照がなく、エラーがスローされます。

このエラーを回避するには:

  1. オブジェクトを操作する前に、常にオブジェクトを初期化してください。
  2. オブジェクトがnullかどうかわからない場合は、で確認してくださいobject == null

JetBrainsのResharperツールは、null参照エラーの可能性があるコード内のすべての場所を識別し、nullチェックを配置できるようにします。このエラーがバグの最大の原因です。


3
JetBrainsのResharperツールは、null参照エラーの可能性があるコード内のすべての場所を識別します。これは誤りです。私はその検出なしの解決策を持っていますが、コードは時々例外を引き起こします。マルチスレッドが関与している場合は、少なくとも検出できないことがありますが、バグの場所がまだ特定されていないため、これ以上コメントすることはできません。
j riv 2018年

しかし、NullReferenceExceptionがHttpContext.Current.Responce.Clear()で使用されたときにそれを解決する方法。上記の解決策のいずれによっても解決されません。HttpContextのその対象オブジェクトの作成中にエラーがまったくアクセス『新』は、引数のこの番号を受け付けていないため、オーバーロードの解決に失敗しました」来るので。
サニーサンディープ

158

これは、コードがnullに設定されたオブジェクト参照変数を使用したことを意味します(つまり、実際のオブジェクトインスタンスを参照していません)。

エラーを回避するには、nullの可能性があるオブジェクトを使用する前にnullをテストする必要があります。

if (myvar != null)
{
    // Go ahead and use myvar
    myvar.property = ...
}
else
{
    // Whoops! myvar is null and cannot be used without first
    // assigning it to an instance reference
    // Attempting to use myvar here will result in NullReferenceException
}

96

シナリオに関係なく、原因は.NETでも常に同じであることに注意してください。

値がNothing/ である参照変数を使用しようとしていますnull。参照変数の値がNothing/の場合、nullそれは実際にはヒープ上に存在するオブジェクトのインスタンスへの参照を保持していないことを意味します。

変数に何かを割り当てたことがないか、変数に割り当てられた値のインスタンスを作成したことがないか、変数をNothing/にnull手動で設定するか、変数をNothing/に設定する関数を呼び出しましたnull


87

スローされるこの例外の例は次のとおりです。何かをチェックしようとしているとき、それはnullです。

例えば:

string testString = null; //Because it doesn't have a value (i.e. it's null; "Length" cannot do what it needs to do)

if (testString.Length == 0) // Throws a nullreferenceexception
{
    //Do something
} 

.NETランタイムは、インスタンス化されていない何か、つまり上記のコードに対してアクションを実行しようとすると、NullReferenceExceptionをスローします。

メソッドに渡されるものがnullではないことをメソッドが期待する場合に、通常は防御策としてスローされるArgumentNullExceptionとは異なります。

詳細については、C#NullReferenceExceptionおよびNull Parameterを参照してください。


87

C#8.0、2019を更新:null可能な参照型

C#8.0では、null許容の参照型null不可の参照型が導入されています。したがって、NullReferenceExceptionを回避するには、null許容の参照型のみをチェックする必要があります。


参照型を初期化しておらず、そのプロパティの1つを設定または読み取る場合は、NullReferenceExceptionがスローされます。

例:

Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.

これは、変数がnullでないかどうかを確認することで簡単に回避できます。

Person p = null;
if (p!=null)
{
    p.Name = "Harry"; // Not going to run to this point
}

NullReferenceExceptionがスローされる理由を完全に理解するには、値タイプと[参照タイプ] [3] の違いを理解することが重要です。

したがって、値型を処理している場合、NullReferenceExceptions 発生しません。ただし、参照型を扱う場合は注意が必要です。

名前が示すように、参照型のみが参照を保持したり、文字どおり何も(または「null」)を指したりできません。一方、値タイプには常に値が含まれます。

参照タイプ(これらはチェックする必要があります):

  • 動的
  • オブジェクト
  • ストリング

値のタイプ(これらは単純に無視できます):

  • 数値型
  • 積分型
  • 浮動小数点型
  • 小数
  • ブール
  • ユーザー定義の構造体

6
-1:質問は「NullReferenceExceptionとは」であるため、値タイプは関係ありません。
John Saunders

21
@ジョンサンダース:私は同意しません。ソフトウェア開発者として、値と参照タイプを区別できることが非常に重要です。そうでなければ、人々は整数がnullかどうかをチェックすることになります。
Fabian

5
確かに、この質問の文脈ではありません。
John Saunders

4
ヒントをありがとう。私はそれを少し改善し、上部に例を追加しました。参照と値のタイプについて言及することは、今でも有用だと思います。
Fabian Bigler、2013年

5
質問は参照型を前提としているため、他の回答にないものは何も追加していないと思います。
ジョンサンダース2013年

78

NullReferenceExceptions起こり得るもう1つのケースは、as演算子の(誤った)使用です。

class Book {
    public string Name { get; set; }
}
class Car { }

Car mycar = new Car();
Book mybook = mycar as Book;   // Incompatible conversion --> mybook = null

Console.WriteLine(mybook.Name);   // NullReferenceException

ここでは、BookCar互換性のないタイプです。をCarに変換/キャストすることはできませんBook。このキャストが失敗すると、をas返しますnull。このmybook後に使用すると、NullReferenceException

通常、as次のようにキャストまたはを使用する必要があります。

型変換が常に成功することを期待している場合(つまり、事前にオブジェクトが何であるかがわかっている場合)、キャストを使用する必要があります。

ComicBook cb = (ComicBook)specificBook;

あなたはタイプが不明ですが、あなたがしたい場合はしようと、特定の型としてそれを使用するために、その後、使用as

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}

2
これは、変数のボックス化を解除するときによく発生します。UI要素のタイプを変更した後、イベントハンドラーで頻繁に発生しますが、コードビハインドの更新を忘れています。
ブレンダン

65

null値参照を含むオブジェクトを使用しています。したがって、null例外が発生します。この例では、文字列値はnullであり、その長さをチェックするときに例外が発生しました。

例:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

例外エラーは次のとおりです。

未処理の例外:

System.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていません。Program.Main()で


1
なんて深い!「null」定数を参照値と見なしたことはありません。これが、C#が "NullPointer"を抽象化する方法です。B / c私がC ++で思い出したように、NPEは、初期化されていないポインター(つまり、c#のref型)を逆参照することによって引き起こされる可能性があります。特に、OSに属している自動初期化を行ったC ++の新しいバージョンでは-fを使用すると、すぐに死ぬ(または単にOSがプロセスを攻撃するシグ​​ニカルをキャッチする))。
samis 2013

64

一方で、何が原因NullReferenceExceptionsをしてまで近づい回避/修正するような例外をどのような多くのプログラマは、まだ学んでいないことはどのように独立であり、他の回答で対処されているデバッグ開発時に、このような例外を。

Visual Studioでは、これはVisual Studio Debuggerのおかげで通常は簡単です。


最初に、正しいエラーがキャッチされることを確認します-VS2010で「System.NullReferenceException」のブレークを許可するにどうすればよいですか?を参照してください 1

次に、デバッグから開始(F5)または[VSデバッガー]を実行中のプロセスにアタッチします。Debugger.Breakデバッガーの起動を促すを使用すると便利な場合があります。

これで、NullReferenceExceptionがスローされる(または処理されない)と、例外が発生した行でデバッガーが停止します(上記のルールセットを覚えていますか?)。時々、エラーは見つけやすいでしょう。

たとえば、次の行で例外が発生する可能ある唯一のコードは、myStringnullと評価される場合です。これは、ウォッチウィンドウを見たり、イミディエイトウィンドウで式を実行したりすることで確認できます。

var x = myString.Trim();

次のようなより高度なケースでは、上記の手法の1つ(ウォッチまたはイミディエイトウィンドウ)を使用して式を調べ、str1nullであるかnullであるかを判断する必要str2があります。

var x = str1.Trim() + str2.Trim();

一度どこ例外がスローが配置されている場合、それはNULL値があった場所を見つけるために理由の後方に、通常は些細だ[誤っ]導入-

例外の原因を理解するのに必要な時間を取ってください。null式を検査します。そのようなnull式をもたらす可能性があった前の式を調べます。ブレークポイントを追加し、必要に応じてプログラムをステップ実行します。デバッガーを使用します。


1 Break on Throwsが非常に積極的で、デバッガーが.NETまたはサードパーティライブラリのNPEで停止した場合、Break on User-Unhandledを使用して、キャッチされる例外を制限できます。さらに、VS2012はJust My Codeを導入しています。これも有効にすることをお勧めします。

Just My Codeを有効にしてデバッグする場合、動作は少し異なります。Just My Codeが有効になっていると、デバッガーはMy Codeの外部でスローされ、My Codeを通過しない初回の共通言語ランタイム(CLR)例外を無視します


59

Simon Mourierがこの例を示しました

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

ここで、アンボクシング変換(キャスト)から object(またはクラスのいずれかから、System.ValueTypeまたはSystem.Enum、またはインターフェイスタイプから)(以外の値型Nullable<>自体には)を与えますNullReferenceException

他の方向では、ボクシングの変換からNullable<>有するHasValueに等しいfalse の参照型は、与えることができnull、後につながることができ参照NullReferenceException。古典的な例は次のとおりです。

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

ボクシングは別の方法で行われることもあります。たとえば、この非ジェネリック拡張メソッドでは、次のようになります。

public static void MyExtension(this object x)
{
  x.ToString();
}

次のコードは問題があります:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

これらのケースは、Nullable<>インスタンスをボックス化するときにランタイムが使用する特別なルールが原因で発生します。


42

エンティティフレームワークで使用されるエンティティのクラス名がWebフォームの分離コードファイルのクラス名と同じである場合のケースの追加。

分離コードクラスがContactであるWebフォームContact.aspxがあり、エンティティ名がContactであるとします。

次に、context.SaveChanges()を呼び出すと、次のコードはNullReferenceExceptionをスローします。

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

完全を期すためにDataContextクラス

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

連絡先エンティティクラス。エンティティクラスは部分クラスであり、他のファイルでも拡張できる場合があります。

public partial class Contact 
{
    public string Name {get; set;}
}

このエラーは、エンティティクラスと分離コードクラスの両方が同じ名前空間にある場合に発生します。これを修正するには、Contact.aspxのエンティティクラスまたは分離コードクラスの名前を変更します。

理由 はまだわかりません。しかし、エンティティクラスのいずれかがSystem.Web.UI.Pageを拡張するたびに、このエラーが発生します。

議論のためにDbContext.saveChanges()のNullReferenceExceptionを見てください


41

この例外を受け取る可能性のあるもう1つの一般的なケースは、ユニットテスト中にクラスをモックすることです。使用されているモックフレームワークに関係なく、クラス階層のすべての適切なレベルが適切にモックされていることを確認する必要があります。特に、HttpContextテスト対象のコードによって参照されるすべてのプロパティはモックする必要があります。

やや冗長な例については、「カスタムAuthorizationAttributeのテスト時にスローされるNullReferenceException」を参照してください。


40

私はこれに答える別の見方をしています。この種の答えは「それを避けるために他に何ができるか?

MVCアプリケーションなど、さまざまなレイヤーで作業する場合、コントローラーにはビジネスオペレーションを呼び出すためのサービスが必要です。このようなシナリオでは、依存性注入コンテナを使用してサービスを初期化し、NullReferenceExceptionを回避できます。つまり、nullのチェックについて心配する必要はなく、コントローラからサービスを呼び出すだけで、シングルトンまたはプロトタイプとして常に利用可能(および初期化)であるかのように処理できます。

public class MyController
{
    private ServiceA serviceA;
    private ServiceB serviceB;

    public MyController(ServiceA serviceA, ServiceB serviceB)
    {
        this.serviceA = serviceA;
        this.serviceB = serviceB;
    }

    public void MyMethod()
    {
        // We don't need to check null because the dependency injection container 
        // injects it, provided you took care of bootstrapping it.
        var someObject = serviceA.DoThis();
    }
}

6
-1:これは単一のシナリオ(初期化されていない依存関係のシナリオ)のみを処理します。これは、NullReferenceExceptionの少数派シナリオです。ほとんどの場合、オブジェクトの動作に関する単純な誤解です。次に最も頻繁に発生するのは、オブジェクトが自動的に初期化されると開発者が想定した他の状況です。
John Saunders

NullReferenceExceptionを回避するために、依存性注入は通常使用されません。ここで一般的なシナリオを見つけたとは思いません。いずれにせよ、あなたが回答をstackoverflow.com/a/15232518/76337のスタイルに変更する場合は、反対票を削除します。
John Saunders

38

問題について「私はそれについて何をすべき」、多くの答えがあることができます。

開発中にそのようなエラー状態防ぐより「正式な」方法は、コードで契約により設計を適用することです。つまり、開発中に、システムにクラス不変式を設定したり、関数/メソッドの前提条件事後条件を設定したりする必要があります。

つまり、クラス不変条件は、通常の使用で違反しないクラスにいくつかの制約があることを保証します(したがって、クラスが不整合な状態になることはありません)。前提条件は、関数/メソッドへの入力として与えられたデータがいくつかの制約セットに従う必要があり、違反しないことを意味し、事後条件は、関数/メソッド出力が設定制約に違反せずに再び従う必要があることを意味します。バグのないプログラムの実行中は契約条件に違反しないでください。したがって、開発モードでは契約による設計がデバッグモードでチェックされ、リリースでは無効になっているため、開発されたシステムパフォーマンスを最大化できます。

このようにしてNullReferenceException、制約セットの違反の結果であるケースを回避できます。たとえばX、クラスでオブジェクトプロパティを使用し、後でそのメソッドの1つを呼び出そうとしてXnull値がある場合、これは次のようになりますNullReferenceException

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

ただし、メソッドの前提条件として「プロパティXにnull値があってはならない」を設定すると、前述のシナリオを回避できます。

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

このため、.NETアプリケーション用のCode Contractsプロジェクトが存在します。

または、契約による設計はアサーションを使用して適用できます。

更新:この用語は、エッフェルプログラミング言語の設計に関連してバートランドマイヤーが造語したことは言及に値します


2
誰もこれを言及しなかったので、これを追加することを考えました、そしてそれがアプローチとして存在する限り、私の意図はトピックを豊かにすることでした。
Nick Louloudakis 2014

2
トピックを充実させてくれてありがとう。私はあなたの追加について私の意見を述べました。今、他の人も同じことができます。
John Saunders

2
これは非常によく見られるスレッドであることを考えると、これはトピックに追加する価値があると思いました。以前にコードコントラクトについて聞いたことがあるので、コードコントラクトの使用を検討することをお勧めします。
VoteCoffee 2015年

36

NullReferenceExceptionnullオブジェクトのプロパティにアクセスしようとしたとき、または文字列値が空になって文字列メソッドにアクセスしようとしたときに、A がスローされます。

例えば:

  1. 空の文字列の文字列メソッドにアクセスした場合:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. nullオブジェクトのプロパティにアクセスした場合:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 

2
これは誤りです。String.Empty.ToLower()null参照例外はスローされません。空の文字列(つまり"")ですが、実際の文字列を表します。これには呼び出すオブジェクトがあるため、ToLower()そこにnull参照例外をスローしても意味がありません。
Kjartan 2015

31

TL; DR:のHtml.Partial代わりに使用してみてくださいRenderpage


次のObject reference not set to an instance of an objectように、モデルを送信してビュー内にビューをレンダリングしようとすると、

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

デバッグにより、モデルがMyOtherView内でNullであることが示されました。私がそれを次のように変更するまで:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

そしてそれはうまくいった。

さらに、私がHtml.Partial最初にする必要がなかった理由は、実際にはエラーではありませんが、別の方法で構成されたループ内にある場合、Visual Studio がエラーに見える波線を下にスローする場合があるためです。Html.Partialforeach

@inherits System.Web.Mvc.WebViewPage
@{
    ViewBag.Title = "Entity Index";
    List<MyEntity> MyEntities = new List<MyEntity>();
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
    MyEntities.Add(new MyEntity());
}
<div>
    @{
        foreach(var M in MyEntities)
        {
            // Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
            @Html.Partial("MyOtherView.cshtml");
        }
    }
</div>

しかし、この「エラー」で問題なくアプリケーションを実行できました。foreachループの構造を次のように変更することで、エラーを取り除くことができました。

@foreach(var M in MyEntities){
    ...
}

Visual Studioがアンパサンドとブラケットを誤って読んでいたためだと感じています。


あなたが欲しかったのHtml.Partialではなく@Html.Partial
ジョン・サンダース

また、例外をスローした行と理由を示してください。
John Saunders

モデルが適切に(それがあったに送信されていなかったため、エラーが、私はここに含まれていませんでしたMyOtherView.cshtml、中に起こったNull。)私は、エラーがどのように私はモデルを送っていたと知っていたので、
トラヴィスHeeter

22

あなたはそれについて何ができますか?

null参照とは何か、それをデバッグする方法を説明する良い答えがたくさんあります。しかし、問題を回避する方法、または少なくとも簡単に検出できるようにする方法はほとんどありません。

引数を確認する

たとえば、メソッドはさまざまな引数をチェックして、それらがnullかどうかを確認し、をスローArgumentNullExceptionできます。これは、まさにこの目的のために作成された例外です。

イベントのコンストラクタArgumentNullExceptionは、パラメータの名前とメッセージを引数として取るので、開発者に問題の内容を正確に伝えることができます。

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

ツールを使用する

役立つライブラリもいくつかあります。たとえば「Resharper」は、コードの作成中に警告を表示できます。特に、それらの属性を使用する場合は、NotNullAttributeを使用できます。

「Microsoftコードコントラクト」では、Contract.Requires(obj != null)ランタイムとコンパイルのチェックを提供するような構文を使用します。コードコントラクトの紹介

次のような属性を使用できる「PostSharp」もあります。

public void DoSometing([NotNull] obj)

そうすることで、ビルド時にPostSharpの一部を作成するobjと、実行時にnullがチェックされます。参照:PostSharp nullチェック

プレーンコードソリューション

または、プレーンな古いコードを使用して、いつでも独自のアプローチをコーディングできます。たとえば、次の例は、null参照をキャッチするために使用できる構造体です。と同じコンセプトでモデル化されていNullable<T>ます:

[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
    private T _value;

    public T Value
    {
        get
        {
            if (_value == null)
            {
                throw new Exception("null value not allowed");
            }

            return _value;
        }
        set
        {
            if (value == null)
            {
                throw new Exception("null value not allowed.");
            }

            _value = value;
        }
    }

    public static implicit operator T(NotNull<T> notNullValue)
    {
        return notNullValue.Value;
    }

    public static implicit operator NotNull<T>(T value)
    {
        return new NotNull<T> { Value = value };
    }
}

Nullable<T>まったく逆のことを実現するという目的を除いて、使用するのと同じように使用できnullます。ここではいくつかの例を示します。

NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null

NotNull<T>暗黙的にキャストされるため、T必要な場所で使用できます。たとえば、を受け取るPersonメソッドにオブジェクトを渡すことができますNotNull<Person>

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull<Person> person)
{
    Console.WriteLine(person.Value.Name);
}

上記のnullableと同様に、Valueプロパティを介して基になる値にアクセスします。または、明示的または暗黙的なキャストを使用できます。以下の戻り値の例を見ることができます。

Person person = GetPerson();

public static NotNull<Person> GetPerson()
{
    return new Person { Name = "John" };
}

または、キャストを実行してメソッドがT(この場合はPerson)戻るだけの場合にも使用できます。たとえば、次のコードは上記のコードと同じです。

Person person = (NotNull<Person>)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

拡張機能と組み合わせる

NotNull<T>拡張メソッドと組み合わせると、さらに多くの状況をカバーできます。以下は、拡張メソッドの例です。

[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
    public static T NotNull<T>(this T @this) where T: class
    {
        if (@this == null)
        {
            throw new Exception("null value not allowed");
        }

        return @this;
    }
}

そして、これがどのように使用されるかの例です:

var person = GetPerson().NotNull();

GitHub

参考までに、GitHubで上記のコードを利用できるようにしました。次の場所にあります。

https://github.com/luisperezphd/NotNull

関連言語機能

C#6.0では、これに少し役立つ「null条件演算子」が導入されました。この機能を使用すると、ネストされたオブジェクトを参照でき、それらのいずれかがnull式全体の場合はを返しますnull

これにより、場合によっては実行する必要があるnullチェックの数が減ります。構文は、各ドットの前に疑問符を付けることです。たとえば、次のコードを見てください。

var address = country?.State?.County?.City;

と呼ばれるプロパティを持つcountryタイプのオブジェクトであると想像してください。もし、、、またはである、その後はnull アドレスnull`なので。CountryStatecountryStateCountyCitynulladdress will be. Therefore you only have to check whetheris

これは優れた機能ですが、情報が少なくなります。4つのうちどれがnullであるかは明確にはなりません。

Nullableのような組み込みですか?

C#にはの省略形がNullable<T>ありますint?。型の後に疑問符を付けることで、何かをnullにできます。

C#にNotNull<T>上記の構造体のようなものがあり、同様の短縮形、おそらく感嘆符(!)があれば、次のように書けると便利ですpublic void WriteName(Person! person)


2
NullReferenceExceptionをスローしない
John Saunders

@JohnSaundersあえて理由を尋ねる?(本当はなぜですか?)
Luis Perez

2
NullReferenceExceptionは、CLRによってスローされることを意図しています。nullへの参照が発生したことを意味します。最初に慎重にチェックした場合を除いて、nullへの参照が発生するという意味ではありません。
John Saunders

それがどのように混乱するかについてのあなたの要点を理解します。この例の通常の例外とGitHubのカスタム例外に更新しました。
Luis Perez

そのような基本的な質問に対する素晴らしい答えです。失敗しているのがコードの場合、それほど悪くはありません。依存している商用サードパーティライブラリの奥深くから来ているのは恐ろしいことであり、カスタマーサポートは、問題を引き起こしているのは自分のコードである必要があると主張し続けています。そして、あなたはそれが確実ではないことを確信しておらず、プロジェクト全体が停止する根拠となっています。
ダレルリー2016

10

興味深いことに、このページの回答はいずれも2つのエッジケースに言及していません。これらを追加しても気にしないでください。

エッジケース#1:辞書への同時アクセス

.NETの汎用ディクショナリはスレッドセーフではないため、2つの同時スレッドからキーにアクセスしようとすると、a またはさらに(より頻繁に)a がスローされることがあります。この場合、例外はかなり誤解を招きます。NullReferenceKeyNotFoundException

エッジケース#2:安全でないコード

コードNullReferenceExceptionによってがスローされた場合はunsafe、ポインタ変数を調べて、IntPtr.Zero何かを確認することができます。これは同じことですが(「nullポインタ例外」)、安全でないコードでは、変数が値型/配列などにキャストされることが多く、壁に頭をぶつけて、値型がこれをスローする方法を疑問に思います例外。

(ちなみに、必要でない限り、安全でないコードを使用しない別の理由)


5
辞書の例は特別なケースではありません。オブジェクトがスレッドセーフでない場合、複数のスレッドから使​​用すると、ランダムな結果が生成されます。安全でないコードの例はnullどの点で異なりますか?
John Saunders

10

C#6のNull条件演算子を使用してクリーンな方法でNullReferenceExceptionを修正し、より少ないコードを記述してnullチェックを処理できます。

メンバーアクセス(?。)またはインデックス(?[)操作を実行する前にnullをテストするために使用されます。

  var name = p?.Spouse?.FirstName;

以下と同等です。

    if (p != null)
    {
        if (p.Spouse != null)
        {
            name = p.Spouse.FirstName;
        }
    }

その結果、pがnullの場合、またはp.Spouseがnullの場合、名前はnullになります。

それ以外の場合、変数名にはp.Spouse.FirstNameの値が割り当てられます。

詳細:ヌル条件演算子


9

「オブジェクト参照がオブジェクトのインスタンスに設定されていません。」というエラー行は、インスタンスオブジェクトをオブジェクト参照に割り当てていないにもかかわらず、そのオブジェクトのプロパティ/メソッドにアクセスしていることを示しています。

たとえば、myClassというクラスがあり、1つのプロパティprop1が含まれているとします。

public Class myClass
{
   public int prop1 {get;set;}
}

次のように、他のクラスでこのprop1にアクセスします。

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

上記の行では、クラスmyClassの参照が宣言されているがインスタンス化されていないか、オブジェクトのインスタンスがそのクラスの参照に割り当てられていないため、エラーがスローされます。

これを修正するには、インスタンス化する必要があります(オブジェクトをそのクラスの参照に割り当てます)。

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}

4

NullReferenceExceptionまたはオブジェクト参照がオブジェクトのインスタンスに設定されていないのは、使用しようとしているクラスのオブジェクトがインスタンス化されていない場合です。例えば:

Studentという名前のクラスがあるとします。

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

ここで、学生のフルネームを取得しようとしている別のクラスを考えてみましょう。

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

上記のコードに見られるように、Student s-ステートメント はタイプStudentの変数のみを宣言します。この時点ではStudentクラスがインスタンス化されていないことに注意してください。したがって、ステートメントs.GetFullName()が実行されると、NullReferenceExceptionがスローされます。


3

まあ、簡単に言えば:

作成されていないか、現在メモリにないオブジェクトにアクセスしようとしています。

これに取り組む方法:

  1. デバッグしてデバッガーを中断させます...中断された変数に直接移動します...ここでの作業は、これを単に修正することです。適切な場所で新しいキーワードを使用します。

  2. オブジェクトが存在しないために一部のデータベースコマンドで発生した場合は、nullチェックを実行してそれを処理するだけです。

    if (i == null) {
        // Handle this
    }
  3. 最も難しいもの.. GCが既にオブジェクトを収集している場合...これは一般的に、文字列を使用してオブジェクトを検索しようとしている場合に発生します...つまり、オブジェクトの名前でオブジェクトを検索すると、GCがすでに発生している可能性があります。クリーンアップしました...これは見つけるのが難しく、かなり問題になります...これに取り組むためのより良い方法は、開発プロセス中に必要に応じてnullチェックを実行することです。これにより、多くの時間を節約できます。

名前で検索するということは、一部のフレームワークでは文字列を使用してFIndObjectsを実行できることを意味し、コードは次のようになります。FindObject( "ObjectName");


3
あなたはオブジェクトへの参照を持っている場合は、GCは、それをクリーンアップすることはありません
ジョン・サンダース

2
FindObject( "Name of Object")のようなものを使用する場合、そのオブジェクトを参照しようとしていることをGCが事前に知る方法はありません..これは説明しようとしていたことです..これらは実行時に発生します
Akash Gutha

2
Unityなど、C#でこの機能を提供するフレームワークがいくつかあります。質問はBClに関連するものは何もありません。批判する前にインターネットを検索してください、それらのような機能がたくさんあります、そしてあなたの親切な情報のために私はそれを毎日使っています。では、答えがどうして意味をなさないのか教えてください。
Akash Gutha

2
docs.unity3d.com/ScriptReference/… リンクを確認し、自分自身を修正しますmr.expert:p
Akash Gutha

リンクで見た例では、GameObject.Findの結果をメンバーフィールドに割り当てています。これは参照であり、GCはそれを含むオブジェクトが収集されるまで収集しません。
John Saunders、2016年

1

文字通り、NullReferenceExeptionを修正する最も簡単な方法には2つの方法があります。たとえば、スクリプトが添付されたGameObjectと、rb(rigidbody)という名前の変数がある場合、ゲームを開始すると、この変数はnullから始まります。
コンピューターがその変数にデータを格納していないため、これがNullReferenceExeptionを取得する理由です。

例としてRigidBody変数を使用します。
いくつかの方法で、データを本当に簡単に追加できます。

  1. AddComponent> Physics> Rigidbodyを使用してRigidBodyをオブジェクトに追加
    し、スクリプトに移動して次のように入力します。rb = GetComponent<Rigidbody>();
    このコード行は、Start()またはAwake()関数の下で最適に機能します。
  2. コンポーネントをプログラムで追加し、1行のコードで同時に変数を割り当てることができます。 rb = AddComponent<RigidBody>();

追記事項:unityでコンポーネントをオブジェクトに追加したいが、コンポーネントを追加するのを忘れた場合は[RequireComponent(typeof(RigidBody))]、クラス宣言の上(すべての使用の下のスペース)に入力できます。
ゲームを楽しんで楽しんでください!


-1

この例外がスローされる可能性のある一般的なシナリオを検討する場合、上部のオブジェクトを使用してプロパティにアクセスします。

例:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

ここでは、アドレスがnullの場合、NullReferenceExceptionが発生します。

そのため、慣例として、そのようなオブジェクト(特に汎用)のプロパティにアクセスする前に、常にnullチェックを使用する必要があります。

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception

-3

これは基本的にnull参照の例外です。マイクロソフト states-

値がnullである型のメンバーにアクセスしようとすると、NullReferenceException例外がスローされます。

どういう意味ですか?

つまり、値を保持していないメンバーがあり、そのメンバーに特定のタスクを実行させている場合、システムは間違いなくメッセージを投げて、

「ちょっと待ってください。そのメンバーには値がないため、あなたが引き渡そうとしているタスクを実行できません。」

例外自体は、何かが参照されているが、その値が設定されていないことを示しています。したがって、これは、値型がnullにできないため、参照型を使用しているときにのみ発生することを示しています。

Value型のメンバーを使用している場合、NullReferenceExceptionは発生しません。

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        Console.WriteLine(str.Length);
        Console.ReadLine();
    }
}

上記のコードは、null値が割り当てられた単純な文字列を示しています

私は、文字列の長さを印刷しようとすると、今、STRを、私は取得しない「System.NullReferenceException」種類の未処理の例外が発生したメンバーのためにメッセージをstrが nullに指しているとヌルの任意の長さがあることはできません。

' NullReferenceException 'は、参照型のインスタンス化を忘れた場合にも発生します。

その中にクラスとメンバーメソッドがあるとします。クラスをインスタンス化せず、クラスに名前を付けただけです。メソッドを使用しようとすると、コンパイラーはエラーをスローするか、警告を発行します(コンパイラーによって異なります)。

class Program
{
    static void Main(string[] args)
    {
        MyClass1 obj;
        obj.foo();  //Use of unassigned local variable 'obj'
    }
}

public class MyClass1
{
    internal void foo()
    {
        Console.WriteLine("hello from foo");

    }
}

上記のコードのコンパイラは、変数objが割り当てられていないというエラーを発生させます。これは、変数にnull値があるか、または何もないことを示します。上記のコードのコンパイラは、変数objが割り当てられていないというエラーを発生させます。これは、変数にnull値があるか、または何もないことを示します。

なぜそれが起こるのですか?

  • NullReferenceExceptionは、オブジェクトの値をチェックしないというフォールトが原因で発生します。コード開発では、オブジェクト値をチェックしないままにすることがよくあります。

  • また、オブジェクトのインスタンス化を忘れたときにも発生します。null値を返すまたは設定できるメソッド、プロパティ、コレクションなどを使用することも、この例外の原因になる可能性があります。

どうすればそれを回避できますか?

この有名な例外を回避するには、さまざまな方法と方法があります。

  1. 明示的なチェック:オブジェクト、プロパティ、メソッド、配列、およびコレクションがnullかどうかをチェックするという伝統に従う必要があります。これは、if-else if-elseなどの条件ステートメントを使用して簡単に実装できます。

  2. 例外処理:この例外を管理する重要な方法の1つ。単純なtry-catch-finallyブロックを使用して、この例外を制御し、そのログを維持することもできます。これは、アプリケーションがプロダクション段階にあるときに非常に役立ちます。

  3. Null演算子:Null Coalescing演算子とnull条件演算子は、オブジェクト、変数、プロパティ、フィールドに値を設定するときにも便利に使用できます。

  4. デバッガー:開発者には、デバッグの大きな武器があります。開発面でNullReferenceExceptionに直面した場合は、デバッガーを使用して例外のソースを取得できます。

  5. 組み込みメソッド:GetValueOrDefault()、IsNullOrWhiteSpace()、IsNullorEmpty()などのシステムメソッドはnullをチェックし、null値がある場合はデフォルト値を割り当てます。

ここにはすでに多くの良い答えがあります。また、私のブログで例を使用して、より詳細な説明を確認することもできます。

これもお役に立てば幸いです。


基本的に、そのブログ投稿の半分をコピーし、既存の回答では対応できない新しいものは何も追加しませんでした。
CodeCaster 2017

@codecaster自分のブログの要約を書き直すときにコピーするということですか。私の答えには何も新しいものはなく、以前の答えにはない新しいものは何もありませんが、より洗練された方法で貢献し、理解した方法を他の人に理解してもらいたいと思います。一人でも役に立てて嬉しいです。誠実に。
Wasim

-4

ビルドの保存またはコンパイル中にこのメッセージが表示された場合は、すべてのファイルを閉じてから、任意のファイルを開いてコンパイルして保存してください。

私にとっての理由は、ファイルの名前を変更し、古いファイルがまだ開いていたためです。

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