私はいくつかのコードを持っていて、それが実行されると、をスローして次のようNullReferenceException
に言います:
オブジェクト参照がオブジェクトインスタンスに設定されていません。
これはどういう意味ですか?このエラーを修正するにはどうすればよいですか?
私はいくつかのコードを持っていて、それが実行されると、をスローして次のようNullReferenceException
に言います:
オブジェクト参照がオブジェクトインスタンスに設定されていません。
これはどういう意味ですか?このエラーを修正するにはどうすればよいですか?
回答:
null
(またはNothing
VB.NETで)何かを使用しようとしています。つまり、に設定null
するか、まったく何も設定しません。
他のように、null
周りに渡されます。それがある場合null
には方法「A」、それはその方法であることができ、「B」は合格null
にメソッド「A」。
null
異なる意味を持つことができます:
NullReferenceException
ます。null
利用可能な意味のある値がないことを示すために意図的に。C#には変数のnull許容データ型の概念があることに注意してください(データベーステーブルはnull許容フィールドを持つことができるように)-変数に割り当てnull
て、値が格納されていないことを示すことができます。たとえばint? a = null;
、疑問符はnullの格納が許可されていることを示します変数a
。if (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行目にをスローstring
しnull
ます。
どのようにしてソースを見つけます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.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;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
プロパティ参照するときに例外が発生した場合@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
コントロールは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
(つまり、label1
前comboBox1
にリストし、設計哲学の問題を無視すると)、少なくともNullReferenceException
ここで解決されます。
as
var myThing = someObject as Thing;
これはスローしませんInvalidCastException
がnull
、キャストが失敗した場合(およびsomeObject
それ自体がnullの場合)を返します。ですので注意してください。
FirstOrDefault()
とSingleOrDefault()
プレーンバージョンでは、何もないときに例外First()
をSingle()
スローします。その場合、「OrDefault」バージョンはnullを返します。ですので注意してください。
foreach
nullコレクションを反復しようとするとスローされます。通常、null
コレクションを返すメソッドからの予期しない結果が原因です。
List<int> list = null;
foreach(var v in list) { } // exception
より現実的な例-XMLドキュメントからノードを選択します。ノードが見つからない場合にスローされますが、初期デバッグではすべてのプロパティが有効であることが示されます。
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
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;
}
null
fromメソッド呼び出しを明示的にチェックし、カスタム例外をスローします。カスタム例外をスローして、呼び出し元のコードでキャッチすることもできます。
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;
}
?.
または?[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>
要素を返します。
C# 8
そこに導入されたnullコンテキストとnullable参照型は、変数の静的分析を実行し、値が潜在的にnullである可能性がある場合、またはnullに設定されている場合にコンパイラ警告を提供します。null可能な参照型により、型を明示的にnullにすることができます。
null可能な注釈コンテキストとnull可能な警告コンテキストはNullable
、csproj
ファイル内の要素を使用してプロジェクトに設定できます。この要素は、コンパイラーが型のNULL可能性を解釈する方法と生成される警告を構成します。有効な設定は次のとおりです。
null可能な参照型は、null可能な値型と同じ構文を使用して示され?
ます。変数の型にa が追加されます。
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
オブジェクトのこの手法が全体で使用されていることがわかります。書くのは少し不格好ですが、ヌルエラーのデバッグがはるかに簡単になります。 作成者の便宜ではなく、呼び出し元の便宜のためにコードを最適化します。
C#
メモリの安全性と型の安全性を提供する通常の安全メカニズムが強制されないため、名前が示すように、非常に危険な「安全でない」モードがあります。メモリがどのように機能するかを十分に理解していない限り、安全でないコードを書くべきではありません。。
安全でないモードでは、2つの重要な事実に注意する必要があります。
その理由を理解するには、最初に.NETがnull逆参照例外を生成する方法を理解することが役立ちます。(これらの詳細は、Windowsで実行されている.NETに適用されます。他のオペレーティングシステムも同様のメカニズムを使用します。)
メモリはで仮想化されWindows
ます。各プロセスは、オペレーティングシステムによって追跡されるメモリの多くの「ページ」の仮想メモリ空間を取得します。メモリの各ページには、読み取り、書き込み、実行など、使用方法を決定するフラグが設定されています。最低ページは、「今までにどのような方法で使用される場合、エラーを生成」としてマークされています。
のnullポインターとnull参照はどちらC#
も内部的にはゼロとして表されるため、対応するメモリストレージに逆参照しようとすると、オペレーティングシステムでエラーが発生します。次に.NETランタイムはこのエラーを検出し、それをnull逆参照例外に変換します。
そのため、nullポインターとnull参照の両方を逆参照すると、同じ例外が発生します。
2番目のポイントはどうですか?いずれかの逆参照仮想メモリの最下位ページにある無効なポインタをと、同じオペレーティングシステムエラーが発生し、同じ例外が発生します。
これはなぜ意味があるのですか?2つの整数を含む構造体と、nullに等しいアンマネージポインターがあるとします。構造体の2番目のintを逆参照CLR
しようとした場合、は場所0のストレージにアクセスしようとしません。ロケーション4のストレージにアクセスします。しかし、論理的にはnull 経由でそのアドレスに到達するため、これはnull逆参照です。
安全でないコードを使用していて、null逆参照例外が発生した場合は、問題のポインタをnullにする必要がないことに注意してください。最下部のページの任意の場所にすることができ、この例外が生成されます。
NullReference Exception
以下のためにのVisual Basicは、 1つの違いはありませんC# 。結局のところ、どちらも.NET Frameworkで定義されている同じ例外を報告しており、どちらも使用しています。Visual Basicに固有の原因はまれです(おそらく1つだけ)。
この回答では、Visual Basicの用語、構文、およびコンテキストを使用します。使用されている例は、過去のスタックオーバーフローに関する多数の質問に基づいています。これは、種類を使用して関連性を最大化することですが多いの記事で見られる状況を。それを必要とするかもしれない人々のために、もう少し説明が提供されます。あなたに似た例がされて非常に可能性がここに記載されています。
注意:
NullReferenceException
(NRE)の原因、それを見つける方法、それを修正する方法、およびそれを回避する方法を理解するのに役立つことを目的としています。NREはさまざまな原因で発生する可能性があるため、これが唯一の遭遇であるとは考えられません。「オブジェクトがオブジェクトのインスタンスに設定されていません」というメッセージは、初期化されていないオブジェクトを使用しようとしていることを意味します。これは、次のいずれかに要約されます。
問題はであるオブジェクト参照なので、Nothing
答えはそれらを調べてどれを見つけるかです。次に、初期化されていない理由を判別します。さまざまな変数の上にマウスを置くと、Visual Studio(VS)にそれらの値が表示されます-原因は次のとおりNothing
です。
また、関連するコード、特にCatchブロックに何もないものから、Try / Catchブロックを削除する必要もあります。これにより、であるオブジェクトを使用しようとすると、コードがクラッシュしますNothing
。これは、問題の正確な場所を特定し、問題の原因となっているオブジェクトを特定できるためです。
MsgBox
表示Error while...
されるキャッチのA はほとんど役に立ちません。この方法も非常に悪いは、実際の例外、関係するオブジェクト、またはそれが発生するコード行さえ記述できないため、スタックオーバーフローの質問ます。
Locals Window
(Debug-> 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
注:コンストラクター()を含め、プロシージャで再度使用しないでください。Dim
Sub 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 Infer
、As <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ための多くの機会を操作(Command
、Connection
、Transaction
、Dataset
、DataTable
、DataRows
....)一度使用中。 注:これは、どのデータプロバイダを使用している問題ではない-の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
以前と同様に、ds
Datasetオブジェクトが宣言されましたが、インスタンスは作成されませんでした。DataAdapter
既存記入しますDataSet
、1を作成していません。この場合、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)
ここでのタイプミスは問題です:Employees
vs 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
Fill
Rows
影響を受ける数も返す関数で、これもテストできます。
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
またはDocument
Nothingであるか、formfld1
要素が存在しない可能性があります。
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 Strict
SQLパラメータも使用します):
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...
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のみの状況です。また、障害のカスケードが発生する可能性があるため、複雑です。
配列とコレクションは、この方法では初期化できません。この初期化コードは、コンストラクターがまたはを作成する前に実行されます。結果として:Form
Controls
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 Function
てReturn 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は、問題の場所を隠し、新しい問題を引き起こす可能性があります。
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ブロックは、例外を修正するための一意の資格を持つ人(開発者)から例外を隠すことを目的としていません。
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
場合CheckBox
とchkName
見つからない(または内に存在するGroupBox
)、次にchk
何もなり、例外が発生する任意のプロパティを参照しようとします。
療法
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
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
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
があるAllowUserToAddRows
とTrue
(デフォルト)、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
当てはまります。
特定の状況下で、であるアイテムを使用しようとすると、初めて使用したときに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
(常に)、常に使用します。
別のシナリオは、nullオブジェクトを値型にキャストする場合です。たとえば、次のコード:
object o = null;
DateTime d = (DateTime)o;
これは、スローされますNullReferenceException
キャストに。上記のサンプルではそれは明らかなようですが、これは、所有していないコードからnullオブジェクトが返され、キャストがたとえば自動システムによって生成された、「遅延バインディング」の複雑なシナリオで発生する可能性があります。
この1つの例は、Calendarコントロールを含む次の単純なASP.NETバインディングフラグメントです。
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
ここでSelectedDate
は、実際にDateTime
は、Calendar
Webコントロールタイプのプロパティ(タイプ)であり、バインディングは何かnullを完全に返す可能性があります。暗黙のASP.NETジェネレーターは、上記のキャストコードと同等のコードを作成します。そして、これはNullReferenceException
うまくコンパイルするASP.NET生成コードにあるため、見つけるのが非常に難しいを発生させます...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
これは、問題の変数が何も指されていないことを意味します。私はこれを次のように生成できます:
SqlConnection connection = null;
connection.Open();
変数 " connection
"を宣言しましたが、何もポイントしていないため、エラーが発生します。メンバー " Open
" を呼び出そうとすると、解決するための参照がなく、エラーがスローされます。
このエラーを回避するには:
object == null
。JetBrainsのResharperツールは、null参照エラーの可能性があるコード内のすべての場所を識別し、nullチェックを配置できるようにします。このエラーがバグの最大の原因です。
これは、コードが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
}
スローされるこの例外の例は次のとおりです。何かをチェックしようとしているとき、それは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を参照してください。
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」)を指したりできません。一方、値タイプには常に値が含まれます。
参照タイプ(これらはチェックする必要があります):
値のタイプ(これらは単純に無視できます):
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
ここでは、Book
とCar
互換性のないタイプです。をCar
に変換/キャストすることはできませんBook
。このキャストが失敗すると、をas
返しますnull
。このmybook
後に使用すると、NullReferenceException
。
通常、as
次のようにキャストまたはを使用する必要があります。
型変換が常に成功することを期待している場合(つまり、事前にオブジェクトが何であるかがわかっている場合)、キャストを使用する必要があります。
ComicBook cb = (ComicBook)specificBook;
あなたはタイプが不明ですが、あなたがしたい場合はしようと、特定の型としてそれを使用するために、その後、使用as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
null値参照を含むオブジェクトを使用しています。したがって、null例外が発生します。この例では、文字列値はnullであり、その長さをチェックするときに例外が発生しました。
例:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
例外エラーは次のとおりです。
未処理の例外:
System.NullReferenceException:オブジェクト参照がオブジェクトのインスタンスに設定されていません。Program.Main()で
一方で、何が原因NullReferenceExceptionsをしてまで近づい回避/修正するような例外をどのような多くのプログラマは、まだ学んでいないことはどのように独立であり、他の回答で対処されているデバッグ開発時に、このような例外を。
Visual Studioでは、これはVisual Studio Debuggerのおかげで通常は簡単です。
最初に、正しいエラーがキャッチされることを確認します-VS2010で「System.NullReferenceException」のブレークを許可するに はどうすればよいですか?を参照してください 。注1
次に、デバッグから開始(F5)または[VSデバッガー]を実行中のプロセスにアタッチします。Debugger.Break
デバッガーの起動を促すを使用すると便利な場合があります。
これで、NullReferenceExceptionがスローされる(または処理されない)と、例外が発生した行でデバッガーが停止します(上記のルールセットを覚えていますか?)。時々、エラーは見つけやすいでしょう。
たとえば、次の行で例外が発生する可能性がある唯一のコードは、myString
nullと評価される場合です。これは、ウォッチウィンドウを見たり、イミディエイトウィンドウで式を実行したりすることで確認できます。
var x = myString.Trim();
次のようなより高度なケースでは、上記の手法の1つ(ウォッチまたはイミディエイトウィンドウ)を使用して式を調べ、str1
nullであるか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)例外を無視します
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<>
インスタンスをボックス化するときにランタイムが使用する特別なルールが原因で発生します。
エンティティフレームワークで使用されるエンティティのクラス名が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を拡張するたびに、このエラーが発生します。
この例外を受け取る可能性のあるもう1つの一般的なケースは、ユニットテスト中にクラスをモックすることです。使用されているモックフレームワークに関係なく、クラス階層のすべての適切なレベルが適切にモックされていることを確認する必要があります。特に、HttpContext
テスト対象のコードによって参照されるすべてのプロパティはモックする必要があります。
やや冗長な例については、「カスタムAuthorizationAttributeのテスト時にスローされるNullReferenceException」を参照してください。
私はこれに答える別の見方をしています。この種の答えは「それを避けるために他に何ができるか?」
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();
}
}
問題について「私はそれについて何をすべき」、多くの答えがあることができます。
開発中にそのようなエラー状態を防ぐより「正式な」方法は、コードで契約により設計を適用することです。つまり、開発中に、システムにクラス不変式を設定したり、関数/メソッドの前提条件や事後条件を設定したりする必要があります。
つまり、クラス不変条件は、通常の使用で違反しないクラスにいくつかの制約があることを保証します(したがって、クラスが不整合な状態になることはありません)。前提条件は、関数/メソッドへの入力として与えられたデータがいくつかの制約セットに従う必要があり、違反しないことを意味し、事後条件は、関数/メソッド出力が設定制約に違反せずに再び従う必要があることを意味します。バグのないプログラムの実行中は契約条件に違反しないでください。したがって、開発モードでは契約による設計がデバッグモードでチェックされ、リリースでは無効になっているため、開発されたシステムパフォーマンスを最大化できます。
このようにして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アプリケーション用のCode Contractsプロジェクトが存在します。
または、契約による設計はアサーションを使用して適用できます。
更新:この用語は、エッフェルプログラミング言語の設計に関連してバートランドマイヤーが造語したことは言及に値します。
NullReferenceException
nullオブジェクトのプロパティにアクセスしようとしたとき、または文字列値が空になって文字列メソッドにアクセスしようとしたときに、A がスローされます。
例えば:
空の文字列の文字列メソッドにアクセスした場合:
string str = string.Empty;
str.ToLower(); // throw null reference exception
nullオブジェクトのプロパティにアクセスした場合:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
null参照例外はスローされません。空の文字列(つまり""
)ですが、実際の文字列を表します。これには呼び出すオブジェクトがあるため、ToLower()
そこにnull参照例外をスローしても意味がありません。
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.Partial
foreach
@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
Null
。)私は、エラーがどのように私はモデルを送っていたと知っていたので、
あなたはそれについて何ができますか?
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`なので。Country
State
country
State
County
City
null
address will be
. Therefore you only have to check whether
is
これは優れた機能ですが、情報が少なくなります。4つのうちどれがnullであるかは明確にはなりません。
Nullableのような組み込みですか?
C#にはの省略形がNullable<T>
ありますint?
。型の後に疑問符を付けることで、何かをnullにできます。
C#にNotNull<T>
上記の構造体のようなものがあり、同様の短縮形、おそらく感嘆符(!)があれば、次のように書けると便利ですpublic void WriteName(Person! person)
。
興味深いことに、このページの回答はいずれも2つのエッジケースに言及していません。これらを追加しても気にしないでください。
.NETの汎用ディクショナリはスレッドセーフではないため、2つの同時スレッドからキーにアクセスしようとすると、a またはさらに(より頻繁に)a がスローされることがあります。この場合、例外はかなり誤解を招きます。NullReference
KeyNotFoundException
コードNullReferenceException
によってがスローされた場合はunsafe
、ポインタ変数を調べて、IntPtr.Zero
何かを確認することができます。これは同じことですが(「nullポインタ例外」)、安全でないコードでは、変数が値型/配列などにキャストされることが多く、壁に頭をぶつけて、値型がこれをスローする方法を疑問に思います例外。
(ちなみに、必要でない限り、安全でないコードを使用しない別の理由)
null
どの点で異なりますか?
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の値が割り当てられます。
詳細:ヌル条件演算子
「オブジェクト参照がオブジェクトのインスタンスに設定されていません。」というエラー行は、インスタンスオブジェクトをオブジェクト参照に割り当てていないにもかかわらず、そのオブジェクトのプロパティ/メソッドにアクセスしていることを示しています。
たとえば、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;
}
}
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がスローされます。
まあ、簡単に言えば:
作成されていないか、現在メモリにないオブジェクトにアクセスしようとしています。
これに取り組む方法:
デバッグしてデバッガーを中断させます...中断された変数に直接移動します...ここでの作業は、これを単に修正することです。適切な場所で新しいキーワードを使用します。
オブジェクトが存在しないために一部のデータベースコマンドで発生した場合は、nullチェックを実行してそれを処理するだけです。
if (i == null) {
// Handle this
}
最も難しいもの.. GCが既にオブジェクトを収集している場合...これは一般的に、文字列を使用してオブジェクトを検索しようとしている場合に発生します...つまり、オブジェクトの名前でオブジェクトを検索すると、GCがすでに発生している可能性があります。クリーンアップしました...これは見つけるのが難しく、かなり問題になります...これに取り組むためのより良い方法は、開発プロセス中に必要に応じてnullチェックを実行することです。これにより、多くの時間を節約できます。
名前で検索するということは、一部のフレームワークでは文字列を使用してFIndObjectsを実行できることを意味し、コードは次のようになります。FindObject( "ObjectName");
文字通り、NullReferenceExeptionを修正する最も簡単な方法には2つの方法があります。たとえば、スクリプトが添付されたGameObjectと、rb(rigidbody)という名前の変数がある場合、ゲームを開始すると、この変数はnullから始まります。
コンピューターがその変数にデータを格納していないため、これがNullReferenceExeptionを取得する理由です。
例としてRigidBody変数を使用します。
いくつかの方法で、データを本当に簡単に追加できます。
rb = GetComponent<Rigidbody>();
Start()
またはAwake()
関数の下で最適に機能します。 rb = AddComponent<RigidBody>();
追記事項:unityでコンポーネントをオブジェクトに追加したいが、コンポーネントを追加するのを忘れた場合は[RequireComponent(typeof(RigidBody))]
、クラス宣言の上(すべての使用の下のスペース)に入力できます。
ゲームを楽しんで楽しんでください!
この例外がスローされる可能性のある一般的なシナリオを検討する場合、上部のオブジェクトを使用してプロパティにアクセスします。
例:
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
これは基本的に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値を返すまたは設定できるメソッド、プロパティ、コレクションなどを使用することも、この例外の原因になる可能性があります。
この有名な例外を回避するには、さまざまな方法と方法があります。
明示的なチェック:オブジェクト、プロパティ、メソッド、配列、およびコレクションがnullかどうかをチェックするという伝統に従う必要があります。これは、if-else if-elseなどの条件ステートメントを使用して簡単に実装できます。
例外処理:この例外を管理する重要な方法の1つ。単純なtry-catch-finallyブロックを使用して、この例外を制御し、そのログを維持することもできます。これは、アプリケーションがプロダクション段階にあるときに非常に役立ちます。
Null演算子:Null Coalescing演算子とnull条件演算子は、オブジェクト、変数、プロパティ、フィールドに値を設定するときにも便利に使用できます。
デバッガー:開発者には、デバッグの大きな武器があります。開発面でNullReferenceExceptionに直面した場合は、デバッガーを使用して例外のソースを取得できます。
組み込みメソッド:GetValueOrDefault()、IsNullOrWhiteSpace()、IsNullorEmpty()などのシステムメソッドはnullをチェックし、null値がある場合はデフォルト値を割り当てます。
ここにはすでに多くの良い答えがあります。また、私のブログで例を使用して、より詳細な説明を確認することもできます。
これもお役に立てば幸いです。
ビルドの保存またはコンパイル中にこのメッセージが表示された場合は、すべてのファイルを閉じてから、任意のファイルを開いてコンパイルして保存してください。
私にとっての理由は、ファイルの名前を変更し、古いファイルがまだ開いていたためです。