コードを実行すると、NullReferenceException
がスローされます:
オブジェクト参照がオブジェクトのインスタンスに設定されていません。
また、このエラーを修正するにはどうしたらいいですか?
あなたはnull
(VB.NETではNothing
)の何かを使おうとしています。つまり、null
に設定するか、まったく何も設定しないかのどちらかです。
他のものと同じように、null
も回される。もし null
in メソッド "A" であれば、メソッド "B" が null
to メソッド "A" に null
を渡したことになります。
nullにはさまざまな意味があります: 1.このようなオブジェクトのプロパティやメソッドにアクセスすると、
NullReferenceExceptionが発生します。 2.2.開発者が意味のある値がないことを示すために、**意図的に
nullを使用している。** C#には変数にnull可能なデータ型の概念があることに注意してください(データベースのテーブルがnull可能なフィールドを持つことができるのと同じです)。if (a.HasValue) {...}
または if (a==null) {...}
で確認できる。この例の a
のような Nullable 変数は、明示的に a.Value
経由で値にアクセスすることも、普通に a
経由でアクセスすることもできます。Value経由でアクセスした場合、
aが
nullであれば
NullReferenceExceptionではなく
InvalidOperationExceptionがスローされます。 この記事の残りの部分では、さらに詳しく、多くのプログラマがよく犯す、
NullReferenceException`につながる間違いを示します。
ランタイムが NullReferenceException
を投げるということは、 常に 同じことを意味する。
これは参照が null
であることを意味し、null
の参照を通して(メソッドなどの)メンバにアクセスすることはできない。最も単純なケースです:
string foo = null;
foo.ToUpper();
なぜなら null
を指す string
参照に対してインスタンスメソッド ToUpper()
を呼び出すことができないからです。
どのようにして NullReferenceException
の原因を見つけるのですか?例外が発生した場所で正確にスローされる例外そのものを見るのは別として、Visual Studioでのデバッグの一般的なルールが適用されます。戦略的なブレークポイントを配置し、変数の検査 を行います。変数名の上にマウスカーソルを置いたり、(クイック)ウォッチウィンドウを開いたり、LocalsやAutosのようなさまざまなデバッグパネルを使用したりします。
参照先がどこに設定されているか、または設定されていないかを調べたい場合は、その名前を右クリックし、"Find All References"を選択します。次に、見つかったすべての場所にブレークポイントを置き、デバッガを接続してプログラムを実行します。このようなブレークポイントでデバッガがブレークするたびに、参照が非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`の新しいインスタンスは作成されません。
public class Person {
public ICollection<Book> Books { get; set; }
}
public class Book {
public string Title { get; set; }
}
ネストされたコレクション・イニシャライザは同じ動作をします:
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のままです。コレクションイニシャライザの構文はコレクションを作成しない。 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
}
}
ローカルとは異なるフィールド名を付けた場合、フィールドを初期化していないことに気づいたかもしれない。
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;
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();
ASP.NET MVC ビューで @Model
のプロパティを参照したときに例外が発生した場合、ビューを return
したときに Model
がアクションメソッドに設定されることを理解する必要があります。コントローラから空のモデル (またはモデルプロパティ) を返すと、ビューからのアクセス時に例外が発生します:
// 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
の呼び出し時に、ビジュアルツリーに表示される順番に作成されます。 イベントハンドラなどを持つコントロールが早期に作成された場合は NullReferenceException
が発生します。InitializeComponent中に発生するイベントハンドラなどが、後から作成されたコントロールを参照している場合、
NullReferenceException`が発生します。
例えば
<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>
ここでは、label1
の前に comboBox1
が作成されます。もし 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をスローしませんが、キャストに失敗した場合(およびsomeObject自体がNULLの場合)にnull
を返します。その点に注意してください。
プレーン・バージョンの First()
と Single()
は、何もないときに例外をスローします。この場合、"OrDefault"バージョンはnullを返す。その点に注意してください。
foreachはヌルコレクションを繰り返し処理しようとするとスローします。通常、コレクションを返すメソッドから予期しない
null` 結果が返されることが原因です。
List<int> list = null;
foreach(var v in list) { } // exception
より現実的な例 - XMLドキュメントからノードを選択します。ノードが見つからなかった場合にスローされますが、最初のデバッグではすべてのプロパティが有効であることを示しています:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
参照が時々 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
を明示的にチェックして、カスタム例外をスローします。カスタム例外をスローして、呼び出し元のコードでキャッチするだけにすることもできます:
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;
}
null
であってはならない場合は Debug.Assert
を使用して、例外が発生する前に問題を検出します。あるメソッドが 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.
}
このチェックはリリースビルドには反映されませんが、リリースモードの実行時にbook == null
のときに再びNullReferenceException
を投げる原因になります。
null
である場合にデフォルト値を提供するために、GetValueOrDefault()
を 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 で使用可能):これはセーフナビゲーション演算子やエルビス演算子と呼ばれることもあります。演算子の左辺の式がNULLの場合、右辺は評価されず、代わりにNULLが返されます。つまり、次のような場合です:
var title = person.Title.ToUpper();
その人に肩書きがない場合、null 値を持つプロパティに対して ToUpper
を呼び出そうとしているため、例外がスローされます。
C# 5以下では、これをガードすることができます:
var title = person.Title == null ? null : person.Title.ToUpper();
これで例外がスローされる代わりに、title変数がnullになります。C# 6では、より短い構文が導入されています:
var title = person.Title?.ToUpper();
person.Titleが
nullの場合、
ToUpperの呼び出しは行われません。 もちろん、
titleがnullであるかどうかをチェックするか、null条件演算子とnull合体演算子(
??`)を使用してデフォルト値を指定する必要があります:
// 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を返し、安全にチェックできます。myIntArrayがnullの場合、式はnullを返し、安全にチェックすることができる: elem=myIntArray[i];`と同じことを行い、ith要素を返します。
C#8で導入されたNULLコンテキストとNULL参照型は、変数の静的解析を行い、値がNULLの可能性がある場合やNULLに設定されている場合にコンパイラに警告を出す。NULL可能な参照型は、型がNULLであることを明示的に許可します。 nullable 注釈コンテキストと nullable 警告コンテキストは、csproj ファイルの Nullable 要素を使用してプロジェクトに設定できます。この要素は、コンパイラーが型の NULL 可 能性をどのように解釈し、どのような警告を生成するかを設定します。有効な設定は以下のとおりです:
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
が呼ばれると、すぐにヌルチェックが行われ、シーケンスが反復処理されるときに GetFrobsForReal
が実行される。
LINQ to Objectsのリファレンスソースを見れば、このテクニックが随所で使われていることがわかるだろう。書くのが少し面倒ですが、ヌルエラーのデバッグが非常に簡単になります。 **作者の都合ではなく、呼び出し側の利便性を考えてコードを最適化しましょう。
C#には"unsafe"モードがあり、メモリ安全性と型安全性を 提供する通常の安全メカニズムが強制されないため、その名の通り非常に危険です。**メモリがどのように機能するかを深く理解していない限り、安全でないコードを書くべきではありません。 安全でないモードでは、2つの重要な事実に注意すべきである:
Visual Basic の「NullReference Exception」は、 C#のものと同じです。 結局のところ、どちらも、両方が使用する.NETフレームワークで定義されている同じ例外を報告しています。 Visual Basicに固有の原因はまれです(おそらく1つだけです)。
この回答では、Visual Basic用語、構文、およびコンテキストを使用します。 使用された例は、過去のStack& nbspの多数の例からのものです。オーバーフローの質問。 これは、投稿でよく見られる状況の種類を使用して、関連性を最大化することです。 それを必要とするかもしれない人々のためにもう少し説明も提供されます。 あなたに似た例が非常にここにリストされている可能性があります。
注意:。
1。 これはコンセプトベースです。プロジェクトに貼り付けるためのコードはありません。 これは、「NullReferenceException」(NRE)の原因、それを見つける方法、修正する方法、およびそれを回避する方法を理解するのに役立つことを目的としています。 NREは多くの方法を引き起こす可能性があるため、これが唯一の出会いになる可能性は低いです。
2。 例(Stack& nbsp; Overflow postsから)は、そもそも何かをするための最良の方法を常に示すとは限りません。
3。 通常、最も単純な治療薬が使用されます。
メッセージ「オブジェクトがオブジェクトのインスタンスに設定されていない」は、初期化されていないオブジェクトを使用しようとしていることを意味します。 これは、次のいずれかに要約されます。
-コードはオブジェクト変数を宣言しましたが、初期化しませんでした(インスタンスを作成するか、それを「*実証」します)。
-コードがオブジェクトを初期化すると想定していたものは、そうしませんでした。
-おそらく、他のコードがまだ使用されているオブジェクトを早期に無効にしました。
問題は「何もない」オブジェクト参照であるため、答えはそれらを調べてどれを見つけるかです。 次に、初期化されていない理由を決定します。 さまざまな変数の上にマウスを置くと、Visual Studio(VS)はその値を表示します-犯人は「何もない」になります。
IDEデバッグディスプレイ。! また、関連するコード、特にキャッチブロックに何もないコードから、トライ/キャッチブロックを削除する必要があります。 これにより、「何もない」オブジェクトを使用しようとすると、コードがクラッシュします。 これはあなたが望むものです問題の正確な場所を識別し、それを引き起こしているオブジェクトを識別できるようになるためです。
間に「エラー」を表示するキャッチの「MsgBox」。..`ほとんど役に立ちません。 この方法は、非常に悪い Stack& nbspにもつながります。実際の例外、関連するオブジェクト、またはそれが発生するコードの行さえ説明できないため、オーバーフローの質問。
Locals Window
( Debug -> Windows -> Locals )を使用してオブジェクトを検査することもできます。
問題が何でどこにあるかがわかったら、通常、修正はかなり簡単で、新しい質問を投稿するよりも高速です。
参照:
-ブレークポイント。
-MSDN:方法:トライ/キャッチブロックを使用して例外をキャッチ。
例と救済。
-。
<。!-language-all:lang-vb -->。
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
を使用します。
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
これにより、そのコンテキスト(サブ)にのみ存在する local 変数 reg
が作成されます。 他の場所で使用するモジュールレベル「スコープ」の「reg」変数は「何もない」のままです。
「新規」オペレーターを欠落させることは、Stack& nbspで見られる「NullReference Exceptions」の最大の原因です。オーバーフローの質問を確認しました。
Visual Basicは、
New
を使用してプロセスを繰り返し明確にしようとします。New
演算子を使用して、 new オブジェクトを作成し、Sub New
を呼び出します-コンストラクター-オブジェクトが他の初期化を実行できる場所。
明確にするために、「Dim」(または「Private」)は変数とその「タイプ」のみを宣言します。 変数のスコープ-モジュール/クラス全体に存在するか、プロシージャにローカルであるか-は、宣言された場所によって決定されます。 プライベート|友達|パブリック
は、スコープではなくアクセスレベルを定義します。
詳細については、以下を参照してください。
---。
配列もインスタンス化する必要があります。
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以降、リテラルと「オプションインファー」を使用してローカル配列を初期化する場合、「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>」が必要です。
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
詳細については、以下を参照してください。
---。
.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)
Classを参照してください。
---。
データベースを操作すると、多くのオブジェクト(「コマンド」、「接続」、「トランザクション」、「データセット」、「データテーブル」、「データ行」)が存在する可能性があるため、NullReferenceには多くの機会があります。...)すぐに使用中。 注:使用しているデータプロバイダーは関係ありません-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」データセットオブジェクトが宣言されましたが、インスタンスが作成されることはありませんでした。 DataAdapter
は既存の DataSet
を埋め、作成しません。 この場合、「ds」はローカル変数であるため、 IDEはこれが発生する可能性があることを警告します。
img。! 「con」の場合のように、モジュール/クラスレベル変数として宣言された場合、コンパイラはオブジェクトがアップストリームプロシージャによって作成されたかどうかを知ることができません。 警告を無視しないでください。
レミディ。
Dim ds As New DataSet
例2 。
ds = New DataSet
da = New OleDBDataAdapter(sql, con)
da.Fill(ds, "Employees")
txtID.Text = ds.Tables("Employee").Rows(0).Item(1)
txtID.Name = ds.Tables("Employee").Rows(0).Item(2)
タイプミスはここで問題です:「従業員」対「従業員」。 「従業員」という名前の「DataTable」は作成されなかったため、「NullReferenceException」の結果にアクセスしようとしました。 別の潜在的な問題は、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")
は存在しないテーブルを参照します。
Remedy は同じです。テーブルをインデックスで参照してください。
If ds.Tables(0).Rows.Count > 0 Then
DataTable Classも参照してください。
---。
If myFoo.Bar.Items IsNot Nothing Then
...
コードは「アイテム」のみをテストしていますが、「myFoo」と「Bar」の両方も何もない場合があります。 remedy は、オブジェクトのチェーン全体またはパスを一度に1つずつテストすることです。
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
「AndAlso」も重要です。 その後のテストは、最初の「False」状態が発生すると実行されません。 これにより、コードが一度に1つの「レベル」でオブジェクトに安全に「ドリル」し、「myFoo」が有効であると判断された後にのみ「myFoo.Bar」を評価できます。 複雑なオブジェクトをコーディングすると、オブジェクトチェーンまたはパスがかなり長くなる可能性があります。
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
「null」オブジェクトの「下流」を参照することはできません。 これはコントロールにも適用されます。
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
ここでは、「myWebBrowser」または「Document」は何もないか、「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は「コントロール」が現在のコンテキストに存在しないか、「非静的メンバーを参照できない」と報告します。 したがって、ある程度、これはVBのみの状況です。 また、カスケードが失敗する可能性があるため、複雑です。 ⁇ アレイやコレクションはこの方法で初期化できません。この初期化コードは、コンストラクターが「フォーム」または「コントロール」を作成する前に実行されます。 結果として:
-リストとコレクションは単に空になります。
-配列には、Nothingの5つの要素が含まれます。
-「somevar」の割り当ては、「。Text」プロパティがないため、すぐにNREになります。
後で配列要素を参照すると、NREになります。 Form_Load
でこれを行うと、奇妙なバグが原因で、IDEは例外が発生したときに報告しない場合があります。 コードが配列を使用しようとすると、例外が後でポップアップします。 この「サイレント例外」はこの投稿の詳細です。 私たちの目的では、重要なのは、フォームの作成中に壊滅的な問題が発生した場合(「サブニュー」または「フォームロード」イベント)、例外が報告されない可能性があることです。コードはプロシージャを終了し、フォームを表示するだけです。
「サブニュー」または「フォームロード」イベントの他のコードは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が警告を提供しないのは不思議ですが、救済策は、フォームレベルでコンテナを宣言することですが、コントロールが do 存在する場合、フォームロードイベントハンドラーでコンテナを初期化します。 これは、コードが「InitializeComponent」呼び出しの後にある限り、「Sub New」で実行できます。
' 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」や「パネル」など)は、「Me.Controls」にはありません。それらは、そのパネルまたはGroupBoxのControlsコレクションに含まれます。 コントロール名のスペルが間違っている場合( " TeStBox2 "
)、コントロールは返されません。 このような場合、「何も」はそれらの配列要素に再度格納され、NREはそれを参照しようとすると発生します。
これらは、探しているものがわかったので、簡単に見つけることができます。
VSはあなたのやり方の誤りを示しています。! 「Button2」は「パネル」にあります。
レミディ。
フォームの「コントロール」コレクションを使用して名前による間接的な参照ではなく、コントロール参照を使用します。
' 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」に置き換えることで警告を抑制できますが、それでも問題は解決しません。 someCondition = False
がNREになるときにリターンを使用しようとすると、次のようになります。
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
レミディ。
関数の「Exit Function」を「Return bList」に置き換えます。 空 リスト
を返すことは、 何も
を返すことと同じではありません。 返されたオブジェクトが「何もない」可能性がある場合は、それを使用する前にテストしてください。
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
これは、オブジェクトが期待どおりに作成されていないケースですが、空の「キャッチ」のカウンターの有用性も示しています。
SQLには(「mailaddress」の後に)追加のカンマがあり、「。ExecuteReader」では例外になります。 Catch
が何も実行しない場合、 Finally
はクリーンアップを実行しようとしますが、null DataReader
オブジェクトを Close
できないため、まったく新しい NullReferenceException
の結果になります。
空の「キャッチ」ブロックは悪魔の遊び場です。 このOPは、彼が「ついに」ブロックでNREを取得した理由に困惑しました。 他の状況では、空の「キャッチ」は、さらに下流に何か他のものを流し込み、問題のために間違った場所で間違ったものを見るのに時間を費やす原因となる場合があります。 (上記の「サイレント例外」は、同じエンターテインメントの価値を提供します。)。
レミディ。
空の試行/キャッチブロックを使用しないでください-a)原因を特定するb)場所を特定する、c)適切な救済策を適用できるように、コードをクラッシュさせます。 試行/キャッチブロックは、例外を修正するために独自に認定された人物(開発者)から例外を隠すことを意図していません。
---。
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
chkName
の CheckBox
が見つからない(または 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
ループを使用する場合は、行数を変更するか、IsNewRow
がtrueの場合は Exit For
を使用します。
---。
特定の状況下では、「StringCollection」である「My.Settings」のアイテムを使用しようとすると、初めて使用するときにNullReferenceが発生する可能性があります。 解決策は同じですが、それほど明白ではありません。 考慮:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
VBが設定を管理しているため、コレクションを初期化することを期待するのは妥当です。 これは可能ですが、以前にコレクションに初期エントリを追加した場合のみです(設定エディター内)。 アイテムが追加されたときにコレクションが(どうやら)初期化されるため、[設定]エディターに追加するアイテムがない場合、コレクションは「何も」のままです。
レミディ。
必要に応じて、フォームの「ロード」イベントハンドラーで設定コレクションを初期化します。
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
通常、「設定」コレクションは、アプリケーションが最初に実行されたときにのみ初期化する必要があります。 別の救済策は、プロジェクト->でコレクションに初期値を追加することです。設定| FooBars 、プロジェクトを保存し、偽の値を削除します。
---。
おそらく「新しい」オペレーターを忘れていました。
または。
初期化されたオブジェクトをコードに戻すために完璧に実行すると想定したものは、実行されませんでした。
コンパイラの警告を無視しないでください(常に)、「オプションの厳格なオン」を使用してください。
---。
別のシナリオは、nullオブジェクトを値タイプにキャストするときです。 たとえば、以下のコード:
object o = null;
DateTime d = (DateTime)o;
キャストに「NullReferenceException」がスローされます。 上記のサンプルでは非常に明白に思われますが、これは、所有していないコードからnullオブジェクトが返され、キャストがたとえば一部の自動システムによって生成される、より「遅延結合」の複雑なシナリオで発生する可能性があります。
この1つの例は、カレンダー制御を備えたこの単純なASP.NETバインディングフラグメントです。
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
ここで、「SelectedDate」は実際には「Calendar」Webコントロールタイプの「DateTime」タイプのプロパティであり、バインディングによって完全に何かが無効になる可能性があります。 暗黙のASP.NETジェネレーターは、上記のキャストコードと同等のコードを作成します。 そして、これはうまくコンパイルされるASP.NET生成コードにあるため、見つけるのが非常に難しい「NullReferenceException」を発生させます。..
これは、問題の変数が何も指していないことを意味する。このように生成することができる:
SqlConnection connection = null;
connection.Open();
なぜなら、変数 "connection
"は宣言されているが、何も指されていないからである。メンバー "Open
" を呼び出そうとしても、解決するための参照がないため、エラーがスローされます。
このエラーを回避するには
1.このエラーを避けるには: 1. オブジェクトを使って何かをしようとする前に、必ずオブジェクトを初期化すること。
2.オブジェクトがnullかどうかわからない場合は、object == null
で確認してください。
JetBrains' Resharperツールは、ヌル参照エラーの可能性があるコード内のすべての場所を特定し、ヌルチェックを行うことができます。このエラーはバグの一番の原因です。
これは、あなたのコードが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
}
シナリオに関係なく、原因は.NET:でも常に同じであることに注意してください。
値が「Nothing」/「null」である参照変数を使用しようとしています。 値が参照変数の「なし」/「null」の場合、ヒープに存在するオブジェクトのインスタンスへの参照を実際に保持していないことを意味します。
変数に何かを割り当てたことがない、変数に割り当てられた値のインスタンスを作成しなかった、または変数を手動で「Nothing」/「null」に設定した、または変数を「Nothing」に設定した関数を呼び出した/
null
あなたのための。
この例外がスローされる例は次のとおりです。何かをチェックしようとすると、それは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 and Null Parameter を参照してください。
C#8.0は、ヌル可能な参照タイプおよびヌル化不可能な参照タイプを導入します。 したがって、 NullReferenceException を回避するために、無効な参照タイプのみをチェックする必要があります。
----------。
参照タイプを初期化しておらず、そのプロパティの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は not 発生する可能性があります。 参照タイプを処理するときは注意が必要です。!
名前が示唆しているように、参照タイプのみが参照を保持したり、文字通り何も指さない(または「null」)ことができます。 一方、値型には常に値が含まれます。
参照タイプ(これらは確認する必要があります):。
-ダイナミック。 -オブジェクト。
値の種類(これらの種類は無視できます):。
-数値タイプ。 -インテグラルタイプ。 -浮動小数点タイプ。 -小数。 -ブール。 -ユーザー定義の構造。
NullReferenceExceptions
が発生する可能性のあるもう1つのケースは、as
operの(誤った)使用です。
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
ここで、「本」と「車」は互換性のないタイプです。 「車」を「本」に変換/キャストすることはできません。 このキャストが失敗すると、「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のおかげで、これは通常簡単です。
---。
まず、正しいエラーがキャッチされることを確認します-参照してください。 https://stackoverflow.com/questions/4475464/ Note 1< / sup> 。
次に、デバッグ(F5)または Attach \ [VSデバッガー]を実行プロセスで開始します。 Debugger.Break
を使用すると、デバッガーの起動を促す場合があります。
これで、NullReferenceExceptionがスロー(または処理されていない)されると、デバッガーが停止します(上記のルールを覚えておいてください)?)例外が発生した回線上。 エラーを簡単に見つけることができる場合があります。
例えば、。 次の行では、例外を発生できる唯一のコードは、「myString」がnullと評価される場合です。 これは、ウォッチウィンドウまたは[即時ウィンドウ]で実行中の式を見て確認できます。 6。
var x = myString.Trim();
次のようなより高度なケースでは、上記の手法のいずれか(ウォッチまたは即時Windows)を使用して式を検査し、「str1」がnullであるか、「str2」がnullであるかを判断する必要があります。
var x = str1.Trim() + str2.Trim();
スローの場所が配置されると、null値が[誤って]どこに導入されたかを知るために、逆方向に推論するのは通常簡単です。
例外の原因を理解するために必要な時間をかけてください。 null式を検査します。 このようなnull式になる可能性のある以前の式を検査します。 ブレークポイントを追加し、必要に応じてプログラムをステップスルーします。 デバッガーを使用します。。
---。
1< / sup> 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
ここで、unboxing変換(キャスト)from object
(またはクラス System.ValueType
または System.Enum
のいずれか、またはインターフェースタイプから)_to_値タイプ( Nullable<>以外)
)それ自体は NullReferenceException
を与えます。
もう一方の方向では、boxing変換from a Nullable<>
は、 HasValue
が false
_to_参照タイプに等しく、後で NullReferenceException
につながる可能性がある null
参照を与えることができます。 古典的な例は次のとおりです。
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.aspx]のWebフォームがあり、そのコードbehindクラスがContactであり、エンティティ名が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を拡張する場合は常に、このエラーが発生します。
ディスカッションについては、https://stackoverflow.com/questions/17136455/nullreferenceexception-in-dbcontext-savechangesをご覧ください。
この例外を受け取る可能性があるもう1つの一般的なケースには、ユニットテスト中にクラスをあざけることが含まれます。 使用されているモッキングフレームワークに関係なく、クラス階層のすべての適切なレベルが適切にモックされていることを確認する必要があります。 特に、テスト中のコードで参照される「HttpContext」のすべてのプロパティは、モックする必要があります。
やや冗長な例については、「カスタムAuthorizationAttributeをテストするときにスローされるNullReferenceException」を参照してください。
私はこれに答えるのとは異なる見方をしています。 この種の回答 "それを回避するために他に何ができますか? "。
たとえばMVCアプリケーションで異なるレイヤー全体で作業する場合、コントローラーはビジネスオペレーションを呼び出すためのサービスを必要とします。 このようなシナリオでは、 Dependency Injection Container を使用してサービスを初期化し、 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アプリケーションには コード契約 プロジェクトが存在します。
または、 アサーション を使用して契約による設計を適用することもできます。
更新:この用語が[エッフェルプログラミング言語の彼のデザインに関連して]バートランドマイヤーによって造られたことは言及する価値があります4。
nullオブジェクトのプロパティにアクセスしようとするとき、または文字列値が空になり、文字列メソッドにアクセスしようとすると、「NullReferenceException」がスローされます。
例:
1。 空の文字列メソッドにアクセスしたとき:
str str = string.Empty;。
str.ToLower(); // null参照例外を投げます。
2。 nullオブジェクトのプロパティにアクセスした場合:
公共クラスの人{。
公開文字列名{取得;セット; }。
}。
人のobjPerson;。
objPerson.Name /// null refernce Exception。
TL; DR:「レンダリングページ」の代わりに「Html.Partial」を使用してみてください。
----------。
このようにモデルを送信してビュー内でビューをレンダリングしようとすると、「オブジェクト参照がオブジェクトのインスタンスに設定されていない」というメッセージが表示されていました。
@{
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」の下にエラーのように見える波線を投げるからです。実際にはエラーではありません。
@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がアンパサンドとブラケットを読み間違えていたからだと思います。
それについて何ができますか?。
ここには、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) `実行時間とコンパイルチェックを提供します:コード契約の導入。
次のような属性を使用できる「PostSharp」もあります。
public void DoSometing([NotNull] obj)
これを実行してビルドプロセスのPostSharp部分を作成することにより、実行時に「obj」がnullに対してチェックされます。 参照:PostSharp null check。
プレーンコードソリューション。
または、プレーンな古いコードを使用して、いつでも独自のアプローチをコーディングできます。 たとえば、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
との間でキャストされるため、必要な場所で使用できます。 たとえば、「人」オブジェクトを「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-conditionalオペレーター」を導入しました。 この機能を使用すると、ネストされたオブジェクトを参照できます。それらのいずれかが「null」の場合、式全体が「null」を返します。
これにより、場合によってはnullチェックを行う必要が減少します。 構文は、各ドットの前に疑問符を付けることです。 たとえば、次のコードを考えてみましょう。
var address = country?.State?.County?.City;
「国」が「国」と呼ばれるプロパティを持つタイプ「国」のオブジェクトであると想像してください。 「国」、「州」、「郡」、または「市」が「null」の場合、「アドレスは「null」になります。 したがって、「アドレス」が「null」であるかどうかを確認するだけです。
これは優れた機能ですが、情報が少なくなります。 4つのうちどれがnullであるかは明らかではありません。
Nullableのような組み込み?。
C#には「Nullable< T>」の優れた省略形があります。このようなタイプの後に疑問符を付けることで、何かを無効にすることができます?`。
C#が上記の NotNull< T>
structのようなもので、同様の省略形、おそらく感嘆符(。!)次のようなものを書くことができるように: public void WriteName(Person。! 人)
。
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の値が割り当てられます。
詳細:全条件演算子。