NullReferenceExceptionとは何ですか、どうすれば修正できますか?

Jan 12 2011

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

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

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

回答

2479 LopDev Jan 11 2011 at 23:52

原因は何ですか?

結論

null(またはNothingVB.NETにある)何かを使用しようとしています。これは、に設定するかnull、まったく設定しないことを意味します。

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

null さまざまな意味を持つことができます:

  1. 初期化されていないため、何も指していないオブジェクト変数この場合、そのようなオブジェクトのプロパティまたはメソッドにアクセスすると、が発生しNullReferenceExceptionます。
  2. 開発者は、使用null可能な意味のある値がないことを示すために意図的に使用しています。C#には変数のnull許容データ型の概念があることに注意してください(データベーステーブルにnull許容フィールドを含めることができるなど)-nullたとえばint? a = null;、疑問符がnullを格納できることを示す場合など、変数に値が格納されていないことを示すために割り当てることができます変数a。で、if (a.HasValue) {...}またはで確認できif (a==null) {...}ます。aこの例のようなNULL可能変数を使用すると、a.Value明示的に、または通常どおりにを介して値にアクセスできますa。if isの代わりにthrowsを介してアクセスすることに
    注意してください。事前にチェックを行う必要があります。つまり、別のnull許容変数がある場合は、以下のような割り当てを行う必要があります。a.ValueInvalidOperationExceptionNullReferenceExceptionanullint 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.Name、で、HttpContext.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.Booksp1.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.

イベント(C#)

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
    }
}

(注:VB.NETコンパイラーは、イベントの使用についてnullチェックを挿入するためNothing、VB.NETでイベントをチェックする必要はありません。)

悪い命名規則:

ローカルとは異なる名前をフィールドに付けた場合、フィールドを初期化したことがないことに気付いたかもしれません。

public class Form1
{
    private Customer customer;
    
    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.NETMVCの空のビューモデル

プロパティ参照するときに例外が発生した場合@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ビジュアルツリーに表示される順序で作成されます。ANullReferenceExceptionは、イベントハンドラーなどを使用して早期に作成されたコントロールの場合に発生し、その間に起動し、その間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のとき)にを返します。ですから、それに注意してください。

LINQFirstOrDefault()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インスタンスメンバーにアクセスする前に参照が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

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

anullが検出されたときにデフォルト値を提供するための省略形:

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で使用可能):

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

var title = person.Title.ToUpper();

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

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

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

これで、title変数は、例外をスローする代わりに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コンテキストとnull許容参照型は、変数の静的分析を実行し、値が潜在的にnullになる可能性がある場合、またはnullに設定されている場合にコンパイラ警告を提供します。null許容参照型を使用すると、型を明示的にnullにすることができます。

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

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

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

イテレータのnullderefをデバッグおよび修正するための特別な手法

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

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オブジェクトの参照ソースを調べると、この手法が全体で使用されていることがわかります。書くのは少し不格好ですが、nullityエラーのデバッグがはるかに簡単になります。作成者の都合ではなく、呼び出し元の都合に合わせてコードを最適化します

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

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

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

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

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

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

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

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

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

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

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

320 Plutonix Nov 05 2014 at 23:08

NullReference例外— Visual Basic

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

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

注意:

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

基本的な意味

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

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

原因を見つける

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

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

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

Locals Window([デバッグ]-> [ウィンドウ]-> [ローカル])を使用してオブジェクトを調べることもできます。

問題が何でどこにあるかがわかれば、通常はかなり簡単に修正でき、新しい質問を投稿するよりも早くできます。

参照:

  • ブレークポイント
  • MSDN:方法:Try / Catchブロックを使用して例外をキャッチする
  • MSDN:例外のベストプラクティス

例と救済

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

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

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

Newオペレーターが見つからないことが、NullReference ExceptionsレビューされたStackOverflowの質問見られる最大の原因です

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

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

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

  • 新しいオペレーター
  • VisualBasicのスコープ
  • VisualBasicのアクセスレベル
  • 値型と参照型

配列

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

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以降、リテラルandを使用してローカル配列を初期化する場合Option InferAs <Type>andNew要素はオプションです。

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

を使用する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

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

  • オプション推論ステートメント
  • VisualBasicのスコープ
  • VisualBasicの配列

リストとコレクション

.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ますが、作成するものではありません。この場合、dsはローカル変数であるため、IDEはこれが発生する可能性があること警告します

の場合のように、モジュール/クラスレベルの変数として宣言された場合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 EmployeeDataTable「従業員」という名前が作成されていないため、NullReferenceExceptionアクセスしようとした結果。もう1つの潜在的な問題は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両方ながらmyFooBarも何もよいです。救済策は一度に全体鎖またはオブジェクト一方のパスをテストすることです。

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またはDocument何もないか、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...


VisualBasicフォーム

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が発生します。

探しているものがわかったので、これらは簡単に見つけることができます。

「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、それは問題を解決していません。リターンを使用しようとする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

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

SQL( 'mailaddress'の後)に余分なコンマがあり、その結果、で例外が発生し.ExecuteReaderます。Catch何もしなかった後、Finallyクリーンアップを実行しようとしますがClose、nullDataReaderオブジェクトを実行できないため、まったく新しい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.DBNull次の値に等しいかどうかをテストするために使用されます。MSDNから:

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)

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

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(常に)使用してください。


MSDNNullReference例外

228 SimonMourier Jun 28 2012 at 19:44

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

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

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

この一例は、Calendarコントロールを使用したこの単純なASP.NETバインディングフラグメントです。

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

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

162 ChrisB.Behrens Jan 11 2011 at 23:52

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

SqlConnection connection = null;
connection.Open();

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

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

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

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

161 JonathanWood Jan 11 2011 at 23:52

これは、コードが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
}
98 codemaster Jan 11 2011 at 23:53

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

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

あなたは、どちらかの変数に割り当てられた値のインスタンスを作成したことがない、変数に何かを割り当てられたことがないか、変数を設定するに等しいNothing/null手動、またはあなたは、変数を設定することを機能と呼ばれるNothing/をnull、あなたのために。

90 FabianBigler May 17 2013 at 04:40

更新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」)を指すことができません。一方、値型には常に値が含まれます。

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

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

値型(これらは無視できます):

  • 数値タイプ
  • 整数型
  • 浮動小数点型
  • 10進数
  • ブール
  • ユーザー定義の構造体
89 AlexKeySmith Jan 11 2011 at 23:53

スローされるこの例外の例は次のとおりです。何かをチェックしようとしているとき、それは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パラメーターを参照してください。

81 JonathonReinhart Mar 06 2013 at 02:32

発生するNullReferenceExceptions可能性のある別のケースは、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は互換性のないタイプです。aCarをに変換/キャストすることはできませんBook。このキャストが失敗すると、をas返しますnull。このmybook後に使用すると、が発生しNullReferenceExceptionます。

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

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

ComicBook cb = (ComicBook)specificBook;

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

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}
67 user1814380 Dec 10 2012 at 16:59

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

例:

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

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

未処理の例外:

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

67 user2864740 Feb 13 2014 at 02:24

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

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


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

次に、デバッグから開始(F5)するか、[VSデバッガー]を実行中のプロセスに接続します。場合によってDebugger.Breakは、デバッガーの起動を求めるプロンプトを表示するを使用すると便利な場合があります。

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

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

var x = myString.Trim();

次のようなより高度なケースでは、上記の手法の1つ(WatchまたはImmediate Windows)を使用して式を調べ、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)例外を無視します。

61 JeppeStigNielsen Jul 10 2014 at 22:43

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<>インスタンスをボックス化するときにランタイムが使用する特別なルールが原因で発生します。

44 AbhinavRanjan Dec 19 2013 at 02:31

エンティティフレームワークで使用されるエンティティのクラス名が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のエンティティクラスまたはcodebehindクラスの名前を変更します。

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

議論については、DbContext.saveChanges()のNullReferenceExceptionを見てください。

43 JohnSaunders Oct 13 2013 at 09:24

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

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

42 Mukus Mar 07 2014 at 06:21

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

たとえば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();
    }
}
40 NickL. Dec 26 2014 at 06:54

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

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

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

このようにして、NullReferenceException設定された制約の違反の結果であるケースを回避できます。たとえばX、クラスでオブジェクトプロパティを使用し、後でそのメソッドの1つを呼び出そうとして、X値がnullの場合、次のようになります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アプリケーション用のコードコントラクトプロジェクトが存在します。

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

更新:この用語は、Eiffelプログラミング言語の設計に関連してBertrandMeyerによって造られたものであることに言及する価値があります。

38 HemantBavle Feb 19 2014 at 02:12

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 
    
33 TravisHeeter Jul 24 2015 at 18:09

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){
    ...
}

VisualStudioがアンパサンドとブラケットを読み間違えたためだと感じていますが。

23 LuisPerez Mar 06 2016 at 23:28

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

ここには、null参照とは何か、およびそれをデバッグする方法を説明する多くの良い答えがあります。しかし、問題を防ぐ方法、または少なくともキャッチしやすくする方法についてはほとんどありません。

引数を確認する

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

ArgumentNullException偶数のコンストラクターは、パラメーターの名前とメッセージを引数として受け取るため、開発者に問題が何であるかを正確に伝えることができます。

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

ツールを使用する

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

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

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

public void DoSometing([NotNull] obj)

これを実行し、PostSharpをビルドプロセスの一部にすることobjで、実行時にnullがチェックされます。参照:PostSharpヌルチェック

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

または、プレーンな古いコードを使用して、いつでも独自のアプローチをコーディングできます。たとえば、これは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必要な場所で使用できます。たとえばPersonNotNull<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)

11 M.Hassan Nov 30 2017 at 06:05

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の値が割り当てられます。

詳細については:ヌル条件演算子

10 jazzcat Mar 23 2017 at 00:57

興味深いことに、このページの回答のいずれも2つのエッジケースについて言及していません。それらを追加しても、誰も気にしないことを願っています。

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

.NETのジェネリック辞書はスレッドセーフでされていないと、彼らは時々投げるかもしれないNullReference、あるいは(より頻繁)KeyNotFoundExceptionあなたは2つの同時スレッドからキーにアクセスしようとします。この場合、例外はかなり誤解を招く可能性があります。

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

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

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

エッジケース#3:プライマリモニターとは異なるDPI設定を持つセカンダリモニターを使用したVisualStudioマルチモニターのセットアップ

このエッジケースはソフトウェア固有であり、Visual Studio 2019 IDE(および場合によっては以前のバージョン)に関係します。

問題を再現する方法:プライマリモニターとは異なるDPI設定の非プライマリモニター上のツールボックスからWindowsフォームにコンポーネントをドラッグすると、「オブジェクト参照がオブジェクトのインスタンスに設定されていません」というポップアップが表示されます。 。」このスレッドによると、この問題はかなり前から知られており、執筆時点ではまだ修正されていません。

9 JaiminDave Mar 08 2017 at 17:58

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

例: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;  
     }
}
5 Nick Jul 28 2016 at 17:52

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がスローされます。

4 AkashChowdary Dec 24 2015 at 14:26

まあ、簡単に言えば:

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

だからこれに取り組む方法:

  1. デバッグしてデバッガーを中断させます...中断された変数に直接移動します...これを修正するだけです。適切な場所でnewキーワードを使用します。

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

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

名前で検索すると、文字列を使用してオブジェクトを検索できるフレームワークがあり、コードは次のようになります。FindObject( "ObjectName");

1 CausticLasagne Nov 15 2017 at 03:17

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

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

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

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