Saya memiliki beberapa kode dan ketika dijalankan, ia melempar NullReferenceException
, mengatakan:
Referensi objek tidak disetel ke instance objek.
Apa artinya ini, dan apa yang bisa saya lakukan untuk memperbaiki kesalahan ini?
Saya memiliki beberapa kode dan ketika dijalankan, ia melempar NullReferenceException
, mengatakan:
Referensi objek tidak disetel ke instance objek.
Apa artinya ini, dan apa yang bisa saya lakukan untuk memperbaiki kesalahan ini?
Jawaban:
Anda mencoba menggunakan sesuatu yang ada null
(atau Nothing
di VB.NET). Ini berarti Anda mengaturnya null
, atau Anda tidak pernah mengaturnya sama sekali.
Seperti yang lainnya, null
akan diedarkan. Jika null
dalam metode "A", bisa jadi metode "B" meneruskan null
ke metode "A".
null
dapat memiliki arti yang berbeda:
NullReferenceException
.null
sengaja untuk menunjukkan tidak ada nilai berarti yang tersedia. Perhatikan bahwa C # memiliki konsep datatypes nullable untuk variabel (seperti tabel database dapat memiliki bidang nullable) - Anda dapat menetapkannya null
untuk menunjukkan tidak ada nilai yang tersimpan di dalamnya, misalnya di int? a = null;
mana tanda tanya menunjukkan bahwa diperbolehkan menyimpan nol dalam variabel a
. Anda dapat memeriksa apakah dengan if (a.HasValue) {...}
atau dengan if (a==null) {...}
. Variabel nullable, seperti a
contoh ini, memungkinkan untuk mengakses nilai melalui a.Value
secara eksplisit, atau sama seperti normal via a
. a.Value
melempar InvalidOperationException
bukan NullReferenceException
jika a
itunull
- Anda harus melakukan pemeriksaan sebelumnya, yaitu jika Anda memiliki variabel on-nullable lain int b;
maka Anda harus melakukan tugas seperti if (a.HasValue) { b = a.Value; }
atau lebih pendek if (a != null) { b = a; }
.Sisa dari artikel ini membahas lebih detail dan menunjukkan kesalahan yang sering dilakukan oleh banyak programmer yang dapat menyebabkan a NullReferenceException
.
The runtime
melemparkan NullReferenceException
selalu berarti hal yang sama: Anda mencoba untuk menggunakan referensi, dan referensi tidak diinisialisasi (atau itu sekali diinisialisasi, tetapi tidak lagi diinisialisasi).
Ini artinya rujukannya null
, dan Anda tidak dapat mengakses anggota (seperti metode) melalui null
rujukan. Kasus paling sederhana:
string foo = null;
foo.ToUpper();
Ini akan melempar NullReferenceException
pada baris kedua karena Anda tidak dapat memanggil metode instance ToUpper()
pada string
referensi yang menunjuk null
.
Bagaimana Anda menemukan sumber NullReferenceException
? Selain melihat pengecualian itu sendiri, yang akan dilemparkan tepat di lokasi di mana itu terjadi, aturan umum debugging di Visual Studio berlaku: tempatkan breakpoint strategis dan periksa variabel Anda , baik dengan mengarahkan mouse di atas nama mereka, membuka ( Cepat) Tonton jendela atau gunakan berbagai panel debug seperti Lokal dan Autos.
Jika Anda ingin mengetahui di mana referensi itu diatur atau tidak, klik kanan namanya dan pilih "Temukan Semua Referensi". Anda kemudian dapat menempatkan breakpoint di setiap lokasi yang ditemukan dan menjalankan program Anda dengan debugger terpasang. Setiap kali debugger memecah breakpoint seperti itu, Anda perlu menentukan apakah Anda mengharapkan referensi tidak nol, memeriksa variabel, dan memverifikasi bahwa itu menunjuk ke sebuah instance ketika Anda mengharapkannya.
Dengan mengikuti alur program dengan cara ini, Anda dapat menemukan lokasi di mana instance tidak boleh null, dan mengapa tidak diatur dengan benar.
Beberapa skenario umum di mana pengecualian dapat dilemparkan:
ref1.ref2.ref3.member
Jika ref1 atau ref2 atau ref3 adalah nol, maka Anda akan mendapatkan NullReferenceException
. Jika Anda ingin menyelesaikan masalah, maka cari tahu yang mana yang nol dengan menulis ulang ekspresi yang sederhananya:
var r1 = ref1;
var r2 = r1.ref2;
var r3 = r2.ref3;
r3.member
Secara khusus, dalam HttpContext.Current.User.Identity.Name
, HttpContext.Current
bisa jadi nol, atau User
properti bisa nol, atau Identity
properti bisa nol.
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.
}
}
Jika Anda ingin menghindari referensi nol anak (Orang), Anda bisa menginisialisasi dalam konstruktor objek orangtua (Buku).
Hal yang sama berlaku untuk inisialisasi objek bersarang:
Book b1 = new Book
{
Author = { Age = 45 }
};
Ini diterjemahkan menjadi
Book b1 = new Book();
b1.Author.Age = 45;
Sementara new
kata kunci digunakan, itu hanya membuat contoh baru Book
, tetapi bukan contoh baru Person
, sehingga Author
properti tetap null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
Koleksi bersarang Initializers
berperilaku sama:
Person p1 = new Person
{
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Ini diterjemahkan menjadi
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
Satu- new Person
satunya yang membuat instance Person
, tetapi Books
koleksinya tetap null
. Initializer
Sintaks koleksi tidak untuk membuat koleksi p1.Books
, itu hanya menerjemahkan ke p1.Books.Add(...)
pernyataan.
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.
kelas publik Form1 {pelanggan Pelanggan pribadi;
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);
}
}
Ini dapat dipecahkan dengan mengikuti konvensi ke bidang awalan dengan garis bawah:
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();
Jika pengecualian terjadi ketika mereferensikan properti @Model
dalam ASP.NET MVC View
, Anda perlu memahami bahwa Model
akan diatur dalam metode tindakan Anda, saat Anda return
melihatnya. Saat Anda mengembalikan model kosong (atau properti model) dari controller Anda, pengecualian terjadi ketika pandangan mengaksesnya:
// 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
kontrol dibuat selama panggilan ke InitializeComponent
dalam urutan mereka muncul di pohon visual. A NullReferenceException
akan dimunculkan dalam kasus kontrol yang dibuat lebih awal dengan pengendali event, dll., Yang terbakar selama InitializeComponent
referensi yang membuat kontrol yang dibuat terlambat.
Sebagai contoh :
<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>
Di sini comboBox1
dibuat sebelumnya label1
. Jika comboBox1_SelectionChanged
upaya untuk mereferensikan `label1, itu belum akan dibuat.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
Mengubah urutan deklarasi dalam XAML
(yaitu, daftar label1
sebelumnya comboBox1
, mengabaikan masalah filosofi desain, setidaknya akan menyelesaikan di NullReferenceException
sini.
as
var myThing = someObject as Thing;
Ini tidak melempar InvalidCastException
tetapi mengembalikan a null
ketika para pemain gagal (dan kapan someObject
itu sendiri nol). Jadi sadarilah itu.
FirstOrDefault()
danSingleOrDefault()
Versi polos First()
dan Single()
melempar pengecualian ketika tidak ada. Versi "OrDefault" mengembalikan null dalam kasus itu. Jadi sadarilah itu.
foreach
melempar ketika Anda mencoba untuk mengembalikan koleksi nol. Biasanya disebabkan oleh null
hasil tak terduga dari metode yang mengembalikan koleksi.
List<int> list = null;
foreach(var v in list) { } // exception
Contoh yang lebih realistis - pilih node dari dokumen XML. Akan melempar jika node tidak ditemukan tetapi debugging awal menunjukkan bahwa semua properti valid:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
dan mengabaikan nilai nol.Jika Anda mengharapkan referensi kadang menjadi nol, Anda dapat memeriksanya null
sebelum mengakses anggota instance:
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
dan berikan nilai default.Metode memanggil Anda berharap untuk kembali contoh dapat kembali null
, misalnya ketika objek yang dicari tidak dapat ditemukan. Anda dapat memilih untuk mengembalikan nilai default saat ini:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
dari panggilan metode dan berikan pengecualian khusus.Anda juga dapat melempar pengecualian khusus, hanya untuk menangkapnya dalam kode panggilan:
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
jika suatu nilai tidak boleh null
, untuk menangkap masalah lebih awal dari pengecualian terjadi.Ketika Anda tahu selama pengembangan bahwa suatu metode mungkin bisa, tetapi tidak harus kembali null
, Anda dapat menggunakannya Debug.Assert()
untuk memecahkan sesegera mungkin ketika itu terjadi:
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.
}
Meskipun pemeriksaan ini tidak akan berakhir di build rilis Anda , menyebabkannya untuk membuang NullReferenceException
lagi ketika book == null
saat runtime dalam mode rilis.
GetValueOrDefault()
untuk nullable
tipe nilai untuk memberikan nilai default saat itu 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 #] atau If()
[VB].Singkatan untuk memberikan nilai default ketika null
ditemui:
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;
}
?.
atau ?[x]
untuk array (tersedia dalam C # 6 dan VB.NET 14):Ini juga kadang-kadang disebut operator navigasi aman atau Elvis (setelah bentuknya). Jika ekspresi di sisi kiri operator adalah nol, maka sisi kanan tidak akan dievaluasi, dan sebaliknya dikembalikan. Itu artinya kasus-kasus seperti ini:
var title = person.Title.ToUpper();
Jika orang tersebut tidak memiliki judul, ini akan menimbulkan pengecualian karena ia mencoba untuk memanggil ToUpper
properti dengan nilai nol.
Di dalam C# 5
dan di bawah, ini dapat dijaga dengan:
var title = person.Title == null ? null : person.Title.ToUpper();
Sekarang variabel judul akan menjadi nol alih-alih melemparkan pengecualian. C # 6 memperkenalkan sintaks yang lebih pendek untuk ini:
var title = person.Title?.ToUpper();
Ini akan menghasilkan variabel judul menjadi null
, dan panggilan ke ToUpper
tidak dilakukan jika person.Title
ada null
.
Tentu saja, Anda masih harus memeriksa title
nol atau menggunakan operator kondisi nol bersama dengan operator penggabungan nol ( ??
) untuk memberikan nilai default:
// 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;
Demikian juga, untuk array Anda dapat menggunakan ?[i]
sebagai berikut:
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Ini akan melakukan hal berikut: Jika myIntArray
bernilai nol, ekspresi mengembalikan nol dan Anda dapat memeriksanya dengan aman. Jika mengandung array, ia akan melakukan hal yang sama seperti:
elem = myIntArray[i];
dan mengembalikan i<sup>th</sup>
elemen.
Diperkenalkan di C# 8
sana konteks nol dan jenis referensi nullable melakukan analisis statis pada variabel dan memberikan peringatan kompilator jika nilai berpotensi nol atau telah diatur ke nol. Jenis referensi yang dapat dibatalkan memungkinkan jenis untuk secara eksplisit diizinkan menjadi nol.
Konteks anotasi yang dapat dibatalkan dan konteks peringatan yang dapat dibatalkan dapat diatur untuk proyek menggunakan Nullable
elemen dalam csproj
file Anda . Elemen ini mengonfigurasikan bagaimana kompiler menafsirkan nullability tipe dan peringatan apa yang dihasilkan. Pengaturan yang valid adalah:
Tipe referensi nullable dicatat menggunakan sintaksis yang sama dengan tipe nilai nullable: a ?
ditambahkan ke tipe variabel.
C#
mendukung "blok iterator" (disebut "generator" dalam beberapa bahasa populer lainnya). Pengecualian null dereference bisa sangat sulit untuk debug di blok iterator karena eksekusi yang ditangguhkan:
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) { ... }
Jika whatever
hasilnya null
maka MakeFrob
akan melempar. Sekarang, Anda mungkin berpikir bahwa hal yang benar untuk dilakukan adalah ini:
// 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();
}
Kenapa ini salah? Karena blok iterator tidak benar - benar berjalan sampai foreach
! Panggilan untuk GetFrobs
hanya mengembalikan objek yang ketika iterasi akan menjalankan blok iterator.
Dengan menulis cek nol seperti ini, Anda mencegah null dereference, tetapi Anda memindahkan pengecualian argumen nol ke titik iterasi , bukan ke titik panggilan , dan itu sangat membingungkan untuk debug .
Perbaikan yang benar adalah:
// 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();
}
Yaitu, buat metode pembantu pribadi yang memiliki logika blok iterator, dan metode permukaan publik yang melakukan pemeriksaan nol dan mengembalikan iterator. Sekarang ketika GetFrobs
dipanggil, pemeriksaan nol terjadi segera, dan kemudian GetFrobsForReal
dijalankan ketika urutan diulang.
Jika Anda memeriksa sumber referensi untuk LINQ
Objek, Anda akan melihat bahwa teknik ini digunakan di seluruh. Menulisnya sedikit lebih kikuk, tetapi itu membuat kesalahan nullging debugging jauh lebih mudah. Optimalkan kode Anda untuk kenyamanan penelepon, bukan kenyamanan penulis .
C#
memiliki mode "tidak aman" yang, seperti namanya, sangat berbahaya karena mekanisme keselamatan normal yang memberikan keamanan memori dan keamanan tipe tidak ditegakkan. Anda tidak boleh menulis kode yang tidak aman kecuali jika Anda memiliki pemahaman yang mendalam dan mendalam tentang cara kerja memori .
Dalam mode tidak aman, Anda harus mengetahui dua fakta penting:
Untuk memahami mengapa hal itu terjadi, ada baiknya untuk memahami bagaimana .NET menghasilkan pengecualian null dereference di tempat pertama. (Detail ini berlaku untuk .NET yang berjalan di Windows; sistem operasi lain menggunakan mekanisme serupa.)
Memori tervirtualisasi dalam Windows
; setiap proses mendapatkan ruang memori virtual dari banyak "halaman" memori yang dilacak oleh sistem operasi. Setiap halaman memori memiliki flag yang ditetapkan di atasnya yang menentukan bagaimana penggunaannya: membaca dari, ditulis ke, dieksekusi, dan sebagainya. The terendah halaman ditandai sebagai "menghasilkan kesalahan jika pernah digunakan dengan cara apapun".
Baik penunjuk nol maupun referensi nol C#
secara internal direpresentasikan sebagai angka nol, dan setiap upaya untuk merujuknya ke penyimpanan memori yang sesuai menyebabkan sistem operasi menghasilkan kesalahan. The .NET runtime kemudian mendeteksi kesalahan ini dan mengubahnya menjadi pengecualian null dereference.
Itu sebabnya dereferencing baik pointer nol dan referensi nol menghasilkan pengecualian yang sama.
Bagaimana dengan poin kedua? Dereferencing setiap pointer tidak valid yang jatuh di halaman terendah memori virtual menyebabkan kesalahan sistem operasi yang sama, dan dengan demikian pengecualian yang sama.
Mengapa ini masuk akal? Nah, misalkan kita memiliki struct yang berisi dua int, dan pointer yang tidak dikelola sama dengan nol. Jika kami mencoba melakukan dereferensi int kedua di struct, ia CLR
tidak akan mencoba mengakses penyimpanan di lokasi nol; itu akan mengakses penyimpanan di lokasi empat. Tapi secara logis ini adalah dereferensi nol karena kita mendapatkan alamat itu melalui nol.
Jika Anda bekerja dengan kode yang tidak aman dan Anda mendapatkan pengecualian null dereference, perlu diketahui bahwa pointer yang menyinggung tidak harus nol. Ini dapat berupa lokasi apa pun di halaman terendah, dan pengecualian ini akan dibuat.
new Book { Author = { Age = 45 } };
Bagaimana bahkan inisialisasi batin ... Saya tidak bisa memikirkan situasi di mana init dalam akan pernah bekerja, namun itu mengkompilasi dan intellisense bekerja ... Kecuali untuk struct?
The NullReference Exception
untuk Visual Basic tidak berbeda dari yang ada di C # . Bagaimanapun, mereka berdua melaporkan pengecualian yang sama yang didefinisikan dalam .NET Framework yang keduanya gunakan. Penyebab unik untuk Visual Basic jarang terjadi (mungkin hanya satu).
Jawaban ini akan menggunakan istilah, sintaks, dan konteks Visual Basic. Contoh yang digunakan berasal dari sejumlah besar pertanyaan Stack Overflow sebelumnya. Ini untuk memaksimalkan relevansi dengan menggunakan jenis situasi yang sering terlihat di posting. Penjelasan lebih banyak juga disediakan bagi mereka yang mungkin membutuhkannya. Contoh yang mirip dengan milik Anda sangat mungkin tercantum di sini.
catatan:
NullReferenceException
(NRE), cara menemukannya, cara memperbaikinya, dan bagaimana cara menghindarinya. NRE dapat disebabkan banyak cara sehingga ini tidak mungkin menjadi satu-satunya pertemuan Anda.Pesan "Objek tidak disetel ke instance Objek" berarti Anda mencoba menggunakan objek yang belum diinisialisasi. Ini bermuara pada salah satu dari ini:
Karena masalahnya adalah referensi objek Nothing
, jawabannya adalah memeriksa mereka untuk mengetahui yang mana. Kemudian tentukan mengapa itu tidak diinisialisasi. Pegang mouse di atas berbagai variabel dan Visual Studio (VS) akan menunjukkan nilainya - biang keladinya Nothing
.
Anda juga harus menghapus blok Coba / Tangkap dari kode yang relevan, terutama yang tidak ada di blok Tangkap. Ini akan menyebabkan kode Anda mogok ketika mencoba menggunakan objek yang Nothing
. Ini yang Anda inginkan karena akan mengidentifikasi lokasi pasti masalah, dan memungkinkan Anda mengidentifikasi objek yang menyebabkannya.
A MsgBox
di Catch yang menampilkan Error while...
akan sedikit membantu. Metode ini juga mengarah ke pertanyaan Stack Overflow yang sangat buruk , karena Anda tidak dapat mendeskripsikan pengecualian aktual, objek yang terlibat, atau bahkan baris kode tempat terjadinya.
Anda juga dapat menggunakan Locals Window
( Debug -> Windows -> Locals ) untuk memeriksa objek Anda.
Setelah Anda tahu apa dan di mana masalahnya, biasanya cukup mudah untuk memperbaiki dan lebih cepat daripada mengirim pertanyaan baru.
Lihat juga:
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Masalahnya adalah bahwa Dim
itu tidak membuat objek CashRegister ; itu hanya mendeklarasikan variabel bernama reg
Tipe itu. Mendeklarasikan variabel objek dan membuat instance adalah dua hal yang berbeda.
Obat
The New
Operator sering dapat digunakan untuk membuat contoh ketika Anda menyatakan hal itu:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Saat yang tepat untuk membuat instance nanti:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Catatan: Jangan gunakan Dim
lagi dalam prosedur, termasuk konstruktor ( Sub New
):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
Ini akan membuat variabel lokalreg
,, yang hanya ada dalam konteks (sub). The reg
variabel dengan tingkat modul Scope
yang akan Anda gunakan sisa-sisa di tempat lain Nothing
.
Kehilangan
New
operator adalah penyebab # 1 yangNullReference Exceptions
terlihat dalam pertanyaan Stack Overflow yang ditinjau.Visual Basic mencoba memperjelas proses berulang kali menggunakan
New
: MenggunakanNew
Operator menciptakan objek baru dan panggilanSub New
- konstruktor - di mana objek Anda dapat melakukan inisialisasi lainnya.
Untuk menjadi jelas, Dim
(atau Private
) hanya mendeklarasikan variabel dan variabelnya Type
. The Lingkup variabel - apakah itu ada untuk seluruh modul / kelas atau lokal untuk prosedur - ditentukan oleh di mana ia dideklarasikan. Private | Friend | Public
mendefinisikan tingkat akses, bukan Lingkup .
Untuk informasi lebih lanjut, lihat:
Array juga harus dipakai:
Private arr as String()
Array ini hanya dideklarasikan, tidak dibuat. Ada beberapa cara untuk menginisialisasi array:
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) {}
Catatan: Dimulai dengan VS 2010, ketika menginisialisasi array lokal menggunakan literal dan Option Infer
, elemen As <Type>
dan New
opsional:
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}
Tipe data dan ukuran array disimpulkan dari data yang ditugaskan. Tingkat deklarasi kelas / Modul masih memerlukan As <Type>
dengan Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Contoh: Array objek kelas
Dim arrFoo(5) As Foo
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i).Bar = i * 10 ' Exception
Next
Array telah dibuat, tetapi Foo
objek di dalamnya belum.
Obat
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Menggunakan List(Of T)
akan membuatnya sangat sulit untuk memiliki elemen tanpa objek yang valid:
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
Untuk informasi lebih lanjut, lihat:
Koleksi .NET (yang ada banyak varietas - Daftar, Kamus, dll.) Juga harus dipakai atau dibuat.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
Anda mendapatkan pengecualian yang sama karena alasan yang sama - myList
hanya dideklarasikan, tetapi tidak ada instance yang dibuat. Obatnya sama:
myList = New List(Of String)
' Or create an instance when declared:
Private myList As New List(Of String)
Pengawasan umum adalah kelas yang menggunakan koleksi 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
Setiap prosedur akan menghasilkan NRE, karena barList
hanya dideklarasikan, tidak dipakai. Menciptakan instance Foo
tidak akan juga membuat instance internal barList
. Mungkin maksud untuk melakukan ini di konstruktor:
Public Sub New ' Constructor
' Stuff to do when a new Foo is created...
barList = New List(Of Bar)
End Sub
Seperti sebelumnya, ini tidak benar:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Untuk informasi lebih lanjut, lihat List(Of T)
Kelas .
Bekerja dengan database hadiah banyak kesempatan untuk NullReference karena akan ada banyak benda ( Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
....) digunakan sekaligus. Catatan: Tidak masalah penyedia data mana yang Anda gunakan - MySQL, SQL Server, OleDB, dll - konsep sama.
Contoh 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
Seperti sebelumnya, ds
objek Dataset dideklarasikan, tetapi sebuah instance tidak pernah dibuat. The DataAdapter
akan mengisi yang ada DataSet
, tidak membuat satu. Dalam hal ini, karena ds
merupakan variabel lokal, IDE memperingatkan Anda bahwa ini mungkin terjadi:
Ketika dideklarasikan sebagai variabel tingkat modul / kelas, seperti yang terlihat dengan kasus con
, kompiler tidak dapat mengetahui apakah objek itu dibuat oleh prosedur hulu. Jangan abaikan peringatan.
Obat
Dim ds As New DataSet
Contoh 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)
Sebuah kesalahan ketik adalah masalah di sini: Employees
vs Employee
. Tidak ada DataTable
nama "Karyawan" yang dibuat, jadi suatu NullReferenceException
hasil mencoba mengaksesnya. Masalah potensial lainnya adalah dengan asumsi akan ada Items
yang mungkin tidak terjadi ketika SQL menyertakan klausa WHERE.
Obat
Karena ini menggunakan satu tabel, penggunaan Tables(0)
akan menghindari kesalahan ejaan. Memeriksa Rows.Count
juga dapat membantu:
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
adalah fungsi mengembalikan jumlah yang Rows
terpengaruh yang juga dapat diuji:
If da.Fill(ds, "Employees") > 0 Then...
Contoh 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
The DataAdapter
akan memberikan TableNames
seperti yang ditunjukkan pada contoh sebelumnya, tetapi tidak nama parse dari SQL atau database meja. Hasil dari,ds.Tables("TICKET_RESERVATION")
referensi tabel tidak ada.
The Remedy adalah sama, referensi tabel dengan indeks:
If ds.Tables(0).Rows.Count > 0 Then
Lihat juga Kelas DataTable .
If myFoo.Bar.Items IsNot Nothing Then
...
Kode hanya menguji Items
sementara keduanya myFoo
dan Bar
mungkin juga Tidak Ada. The obat adalah untuk menguji seluruh rantai atau jalur objek satu per satu:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
penting. Tes selanjutnya tidak akan dilakukan setelah False
kondisi pertama ditemui. Ini memungkinkan kode untuk dengan aman 'menelusuri' ke objek satu tingkat di satu waktu, mengevaluasi myFoo.Bar
hanya setelah (dan jika) myFoo
ditentukan valid. Rantai atau lintasan objek bisa menjadi cukup lama ketika mengkode objek kompleks:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Tidak mungkin untuk merujuk apa pun 'hilir' dari suatu null
objek. Ini juga berlaku untuk kontrol:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Di sini, myWebBrowser
atau Document
bisa jadi Tidak ada atau formfld1
elemen mungkin tidak ada.
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)
Antara lain, kode ini tidak mengantisipasi bahwa pengguna mungkin tidak memilih sesuatu dalam satu atau lebih kontrol UI. ListBox1.SelectedItem
mungkin Nothing
, jadi ListBox1.SelectedItem.ToString
akan menghasilkan NRE.
Obat
Validasi data sebelum menggunakannya (juga gunakan Option Strict
dan parameter 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
Atau, Anda dapat menggunakan (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
Ini adalah cara yang cukup umum untuk mendapatkan NRE. Dalam C #, tergantung pada bagaimana dikodekan, IDE akan melaporkan yang Controls
tidak ada dalam konteks saat ini, atau "tidak dapat merujuk anggota non-statis". Jadi, sampai batas tertentu, ini hanya situasi VB. Ini juga kompleks karena dapat mengakibatkan kegagalan kaskade.
Array dan koleksi tidak dapat diinisialisasi dengan cara ini. Kode inisialisasi ini akan berjalan sebelum konstruktor membuat Form
atau Controls
. Hasil dari:
somevar
tugas akan menghasilkan NRE segera karena ada tidak memiliki .Text
propertiMerujuk elemen array nanti akan menghasilkan NRE. Jika Anda melakukan ini Form_Load
, karena bug aneh, IDE tidak dapat melaporkan pengecualian ketika itu terjadi. Pengecualian akan muncul nanti ketika kode Anda mencoba menggunakan array. "Pengecualian sunyi" ini dirinci dalam pos ini . Untuk tujuan kami, kuncinya adalah bahwa ketika sesuatu bencana terjadi saat membuat formulir ( Sub New
atau Form Load
peristiwa), pengecualian mungkin tidak dilaporkan, kode keluar dari prosedur dan hanya menampilkan formulir.
Karena tidak ada kode lain di Anda Sub New
atau Form Load
acara akan berjalan setelah NRE tersebut, banyak hal lain dapat dibiarkan uninitialized.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Catatan ini berlaku untuk setiap dan semua kontrol dan referensi komponen membuat ini ilegal di mana mereka berada:
Public Class Form1
Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
Private studentName As String = TextBox13.Text
Obat Parsial
Sangat mengherankan bahwa VB tidak memberikan peringatan, tetapi obatnya adalah dengan mendeklarasikan kontainer pada level form, tetapi menginisialisasi mereka dalam form load event handler ketika kontrol benar-benar ada. Ini dapat dilakukan Sub New
selama kode Anda setelah InitializeComponent
panggilan:
' 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
Kode array mungkin belum keluar dari hutan. Kontrol apa pun yang ada dalam kontrol wadah (seperti a GroupBox
atau Panel
) tidak akan ditemukan di Me.Controls
; mereka akan berada di koleksi Kontrol Panel atau GroupBox itu. Kontrol juga tidak akan dikembalikan ketika nama kontrol salah eja ( "TeStBox2"
). Dalam kasus seperti itu, Nothing
sekali lagi akan disimpan dalam elemen array tersebut dan NRE akan dihasilkan ketika Anda mencoba untuk referensi itu.
Ini seharusnya mudah ditemukan sekarang setelah Anda tahu apa yang Anda cari:
"Button2" berada di a Panel
Obat
Daripada referensi tidak langsung dengan nama menggunakan Controls
koleksi formulir , gunakan referensi kontrol:
' 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
Ini adalah kasus di mana IDE akan memperingatkan Anda bahwa ' tidak semua jalur mengembalikan nilai dan NullReferenceException
hasil dapat '. Anda dapat menekan peringatan, dengan mengganti Exit Function
dengan Return Nothing
, tetapi itu tidak memecahkan masalah. Apa pun yang mencoba menggunakan pengembalian ketika someCondition = False
akan menghasilkan NRE:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
Obat
Ganti Exit Function
fungsi dengan Return bList
. Mengembalikan kosong List
tidak sama dengan mengembalikan Nothing
. Jika ada kemungkinan objek yang dikembalikan dapat Nothing
, uji sebelum menggunakannya:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Try / Catch yang diimplementasikan dengan buruk dapat menyembunyikan di mana masalahnya dan menghasilkan yang baru:
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
Ini adalah kasus objek tidak dibuat seperti yang diharapkan, tetapi juga menunjukkan manfaat kontra dari yang kosong Catch
.
Ada koma tambahan di SQL (setelah 'alamat surat') yang menghasilkan pengecualian di .ExecuteReader
. Setelah Catch
tidak melakukan apa-apa, Finally
cobalah untuk melakukan pembersihan, tetapi karena Anda tidak dapat objek Close
nol DataReader
, NullReferenceException
hasil baru .
Catch
Blok kosong adalah taman bermain iblis. OP ini bingung mengapa dia mendapatkan NRE di Finally
blok. Dalam situasi lain, sebuah kekosongan Catch
dapat mengakibatkan sesuatu yang lebih jauh ke hilir menjadi berantakan dan menyebabkan Anda menghabiskan waktu melihat hal-hal yang salah di tempat yang salah untuk masalah tersebut. ("Pengecualian sunyi" yang dijelaskan di atas memberikan nilai hiburan yang sama.)
Obat
Jangan gunakan blok Coba / Tangkap kosong - biarkan kode macet sehingga Anda dapat a) mengidentifikasi penyebab b) mengidentifikasi lokasi dan c) menerapkan obat yang tepat. Blok Coba / Tangkap tidak dimaksudkan untuk menyembunyikan pengecualian dari orang yang memiliki kualifikasi unik untuk memperbaikinya - pengembang.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
The IsDBNull
Fungsi ini digunakan untuk menguji apakah nilai sama System.DBNull
: Dari MSDN:
Nilai System.DBNull menunjukkan bahwa Objek mewakili data yang hilang atau tidak ada. DBNull tidak sama dengan Tidak Ada, yang menunjukkan bahwa variabel belum diinisialisasi.
Obat
If row.Cells(0) IsNot Nothing Then ...
Seperti sebelumnya, Anda dapat menguji Tidak Ada, kemudian untuk nilai tertentu:
If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then
Contoh 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
mengembalikan item pertama atau nilai default, yang Nothing
untuk tipe referensi dan tidak pernah DBNull
:
If getFoo IsNot Nothing Then...
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
Jika sebuah CheckBox
dengan chkName
tidak dapat ditemukan (atau ada di a GroupBox
), maka chk
akan menjadi Apa-apa dan berusaha untuk referensi properti apa pun akan menghasilkan pengecualian.
Obat
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
DGV memiliki beberapa kebiasaan yang dilihat secara berkala:
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"
Jika dgvBooks
sudah AutoGenerateColumns = True
, itu akan membuat kolom, tetapi tidak menamai mereka, jadi kode di atas gagal ketika referensi mereka dengan nama.
Obat
Beri nama kolom secara manual, atau referensi berdasarkan indeks:
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
Ketika Anda DataGridView
memiliki AllowUserToAddRows
as True
(default), Cells
baris kosong / baru di bagian bawah semuanya akan berisi Nothing
. Sebagian besar upaya untuk menggunakan konten (misalnya, ToString
) akan menghasilkan NRE.
Obat
Gunakan For/Each
perulangan dan uji IsNewRow
properti untuk menentukan apakah itu baris terakhir. Ini berfungsi baik AllowUserToAddRows
benar atau tidak:
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Jika Anda menggunakan For n
loop, modifikasi jumlah baris atau gunakan Exit For
kapan IsNewRow
benar.
Dalam keadaan tertentu, mencoba menggunakan item My.Settings
yang StringCollection
dapat menghasilkan NullReference saat pertama kali Anda menggunakannya. Solusinya sama, tetapi tidak sejelas itu. Mempertimbangkan:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
Karena VB mengelola Pengaturan untuk Anda, masuk akal untuk mengharapkannya untuk menginisialisasi koleksi. Itu akan, tetapi hanya jika Anda sebelumnya telah menambahkan entri awal ke koleksi (di Editor pengaturan). Karena koleksi (tampaknya) diinisialisasi ketika item ditambahkan, ia tetap Nothing
ketika tidak ada item dalam editor Pengaturan untuk ditambahkan.
Obat
Inisialisasi koleksi pengaturan di Load
pengendali acara formulir , jika / ketika dibutuhkan:
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Biasanya, Settings
koleksi hanya perlu diinisialisasi saat pertama kali aplikasi dijalankan. Obat alternatif adalah menambahkan nilai awal ke koleksi Anda di Proyek -> Pengaturan | FooBars , simpan proyek, lalu hapus nilai palsu.
Anda mungkin lupa New
operatornya.
atau
Sesuatu yang Anda asumsikan akan tampil sempurna untuk mengembalikan objek yang diinisialisasi ke kode Anda, tidak.
Jangan abaikan peringatan kompiler (selalu) dan gunakan Option Strict On
(selalu).
Skenario lain adalah ketika Anda melemparkan objek nol ke dalam tipe nilai . Misalnya, kode di bawah ini:
object o = null;
DateTime d = (DateTime)o;
Ini akan melempar NullReferenceException
pada pemain. Tampaknya cukup jelas dalam sampel di atas, tetapi ini dapat terjadi dalam skenario rumit yang lebih "mengikat" di mana objek null telah dikembalikan dari beberapa kode yang tidak Anda miliki, dan para pemain misalnya dihasilkan oleh beberapa sistem otomatis.
Salah satu contohnya adalah fragmen pengikat ASP.NET sederhana ini dengan kontrol Kalender:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Di sini, SelectedDate
sebenarnya adalah properti - DateTime
tipe - dari Calendar
tipe Kontrol Web, dan pengikatan dengan sempurna dapat mengembalikan sesuatu yang nol. ASP.NET Generator implisit akan membuat sepotong kode yang akan setara dengan kode pemain di atas. Dan ini akan meningkatkan NullReferenceException
yang cukup sulit dikenali, karena terletak pada kode ASP.NET yang dihasilkan yang mengkompilasi ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Ini berarti bahwa variabel yang dipermasalahkan tidak menunjuk apa-apa. Saya dapat menghasilkan ini seperti ini:
SqlConnection connection = null;
connection.Open();
Itu akan membuang kesalahan karena sementara saya sudah mendeklarasikan variabel " connection
", itu tidak menunjuk ke apa pun. Ketika saya mencoba memanggil anggota " Open
", tidak ada referensi untuk diselesaikan, dan itu akan menimbulkan kesalahan.
Untuk menghindari kesalahan ini:
object == null
.Alat Resharper JetBrains akan mengidentifikasi setiap tempat dalam kode Anda yang memiliki kemungkinan kesalahan referensi nol, memungkinkan Anda untuk memasukkan cek nol. Kesalahan ini adalah sumber bug nomor satu, IMHO.
Ini berarti kode Anda menggunakan variabel referensi objek yang disetel ke nol (artinya tidak mereferensikan instance objek aktual).
Untuk mencegah kesalahan, objek yang bisa null harus diuji untuk null sebelum digunakan.
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
}
Perlu diketahui bahwa terlepas dari skenario, penyebabnya selalu sama di .NET:
Anda mencoba menggunakan variabel referensi yang nilainya adalah
Nothing
/null
. Ketika nilainya adalahNothing
/null
untuk variabel referensi, itu berarti ia tidak benar-benar memegang referensi ke instance objek apa pun yang ada di heap.Anda tidak pernah menugaskan sesuatu ke variabel, tidak pernah membuat instance dari nilai yang diberikan ke variabel, atau Anda mengatur variabel sama dengan
Nothing
/null
secara manual, atau Anda memanggil fungsi yang mengatur variabel keNothing
/null
untuk Anda.
Contoh pengecualian ini yang dilemparkan adalah: Ketika Anda mencoba untuk memeriksa sesuatu, itu adalah nol.
Sebagai contoh:
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
}
The .NET runtime akan melempar NullReferenceException ketika Anda mencoba untuk melakukan suatu tindakan pada sesuatu yang belum dipakai misalnya kode di atas.
Dibandingkan dengan ArgumentNullException yang biasanya dilemparkan sebagai tindakan defensif jika suatu metode mengharapkan bahwa apa yang diteruskan ke sana bukan nol.
Informasi lebih lanjut ada di C # NullReferenceException dan Null Parameter .
Pembaruan C # 8.0, 2019: Jenis referensi tidak dapat dibatalkan
C # 8.0 memperkenalkan jenis referensi yang dapat dibatalkan dan jenis referensi yang tidak dapat dibatalkan . Jadi hanya jenis referensi yang dapat dibatalkan yang harus diperiksa untuk menghindari NullReferenceException .
Jika Anda belum menginisialisasi tipe referensi, dan Anda ingin mengatur atau membaca salah satu propertinya, ia akan melempar NullReferenceException .
Contoh:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Anda bisa menghindari ini dengan memeriksa apakah variabelnya bukan nol:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
Untuk memahami sepenuhnya mengapa NullReferenceException dilemparkan, penting untuk mengetahui perbedaan antara tipe nilai dan [tipe referensi] [3].
Jadi, jika Anda berurusan dengan tipe nilai , NullReferenceExceptions tidak dapat terjadi. Meskipun Anda harus tetap waspada ketika berhadapan dengan jenis referensi !
Hanya tipe referensi, seperti yang disarankan namanya, dapat menahan referensi atau menunjukkan apa-apa (atau 'nol'). Sedangkan tipe nilai selalu mengandung nilai.
Jenis referensi (yang ini harus diperiksa):
Jenis nilai (Anda dapat mengabaikannya):
Kasus lain yang NullReferenceExceptions
dapat terjadi adalah penggunaan (salah) as
operator :
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
Di sini, Book
dan Car
merupakan tipe yang tidak kompatibel; a Car
tidak dapat dikonversi / dilemparkan ke a Book
. Ketika para pemeran ini gagal, as
kembali null
. Penggunaan mybook
setelah ini menyebabkan a NullReferenceException
.
Secara umum, Anda harus menggunakan gips atau as
, sebagai berikut:
Jika Anda mengharapkan konversi tipe selalu berhasil (mis. Anda tahu objek apa yang harus ada sebelumnya), maka Anda harus menggunakan pemeran:
ComicBook cb = (ComicBook)specificBook;
Jika Anda tidak yakin dengan jenisnya, tetapi Anda ingin mencoba menggunakannya sebagai jenis tertentu, maka gunakan as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Anda menggunakan objek yang berisi referensi nilai nol. Jadi itu memberikan pengecualian nol. Dalam contoh nilai string adalah nol dan ketika memeriksa panjangnya, pengecualian terjadi.
Contoh:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
Kesalahan pengecualian adalah:
Pengecualian Tidak Tertangani:
System.NullReferenceException: Referensi objek tidak disetel ke instance objek. di Program.Main ()
Sementara apa yang menyebabkan NullReferenceExceptions dan pendekatan untuk menghindari / memperbaiki pengecualian tersebut telah diatasi dalam jawaban lain, apa yang belum dipelajari oleh banyak programmer adalah bagaimana cara secara independen men - debug pengecualian seperti itu selama pengembangan.
Dalam Visual Studio ini biasanya mudah berkat Debugger Visual Studio .
Pertama, pastikan bahwa kesalahan yang benar akan ditangkap - lihat Bagaimana cara saya membolehkan melanggar pada 'System.NullReferenceException' di VS2010? Catatan 1
Kemudian Mulai dengan Debugging (F5) atau Lampirkan [Debugger VS] untuk Menjalankan Proses . Kadang-kadang mungkin berguna untuk digunakan Debugger.Break
, yang akan mendorong untuk meluncurkan debugger.
Sekarang, ketika NullReferenceException dilempar (atau tidak ditangani) debugger akan berhenti (ingat aturan yang ditetapkan di atas?) Pada baris di mana pengecualian terjadi. Terkadang kesalahan akan mudah dikenali.
Misalnya, pada baris berikut, satu-satunya kode yang dapat menyebabkan pengecualian adalah jika myString
bernilai nol. Ini dapat diverifikasi dengan melihat Jendela Tonton atau menjalankan ekspresi di Jendela Segera .
var x = myString.Trim();
Dalam kasus yang lebih maju, seperti berikut ini, Anda harus menggunakan salah satu teknik di atas (Tonton atau Segera Windows) untuk memeriksa ekspresi untuk menentukan apakah str1
itu nol atau jika str2
itu nol.
var x = str1.Trim() + str2.Trim();
Setelah di mana pengecualian adalah lemparan telah ditemukan, biasanya sepele untuk mundur alasan untuk mencari tahu di mana nilai null itu [salah] diperkenalkan -
Luangkan waktu yang dibutuhkan untuk memahami penyebab pengecualian. Periksa untuk ekspresi nol. Periksa ekspresi sebelumnya yang bisa menghasilkan ekspresi nol seperti itu. Tambahkan breakpoints dan melangkah melalui program yang sesuai.Gunakan debugger.
1 Jika Break on Throws terlalu agresif dan debugger berhenti pada NPE di pustaka .NET atau pihak ketiga, Break on User-Unhandled dapat digunakan untuk membatasi pengecualian yang tertangkap. Selain itu, VS2012 memperkenalkan Just My Code yang saya sarankan aktifkan juga.
Jika Anda men-debug dengan Just My Code diaktifkan, perilaku ini sedikit berbeda. Dengan Just My Code diaktifkan, debugger mengabaikan pengecualian runtime bahasa umum (CLR) kesempatan pertama yang dibuang di luar Kode Saya dan tidak melewati Kode Saya
Simon Mourier memberi contoh ini :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
di mana konversi unboxing (dilemparkan) dari object
(atau dari salah satu kelas System.ValueType
atau System.Enum
, atau dari tipe antarmuka) ke tipe nilai (selain Nullable<>
) dengan sendirinya memberikan NullReferenceException
.
Di arah lain, sebuah tinju konversi dari suatu Nullable<>
yang memiliki HasValue
sama false
untuk tipe referensi, dapat memberikan null
referensi yang kemudian dapat kemudian menyebabkan NullReferenceException
. Contoh klasik adalah:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Terkadang tinju terjadi dengan cara lain. Misalnya dengan metode ekstensi non-generik ini:
public static void MyExtension(this object x)
{
x.ToString();
}
kode berikut akan bermasalah:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Kasus-kasus ini muncul karena aturan khusus yang digunakan runtime ketika Nullable<>
instance tinju .
Menambahkan kasus ketika nama kelas untuk entitas yang digunakan dalam kerangka entitas sama dengan nama kelas untuk file kode-belakang formulir web.
Misalkan Anda memiliki formulir web Contact.aspx yang kelas codebehindnya adalah Kontak dan Anda memiliki nama entitas Kontak.
Kemudian kode berikut akan melempar NullReferenceException ketika Anda memanggil context.SaveChanges ()
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Demi kelengkapan kelas DataContext
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
dan kelas entitas kontak. Kadang-kadang kelas entitas adalah kelas parsial sehingga Anda dapat memperluas mereka di file lain juga.
public partial class Contact
{
public string Name {get; set;}
}
Kesalahan terjadi ketika kedua entitas dan kelas codebehind berada di namespace yang sama. Untuk memperbaikinya, ganti nama kelas entitas atau kelas kode kode untuk Contact.aspx.
Alasan saya masih belum yakin tentang alasannya. Tetapi setiap kali kelas entitas akan memperpanjang System.Web.UI.Page kesalahan ini terjadi.
Untuk diskusi, lihat NullReferenceException di DbContext.saveChanges ()
Kasus umum lain di mana orang mungkin menerima pengecualian ini melibatkan kelas mengejek selama pengujian unit. Terlepas dari kerangka mengejek yang digunakan, Anda harus memastikan bahwa semua level hirarki kelas yang sesuai diejek dengan benar. Secara khusus, semua properti dariHttpContext
yang dirujuk oleh kode yang diuji harus diejek.
Lihat " NullReferenceException yang dilemparkan ketika menguji custom AuthorizationAttribute " untuk contoh yang agak bertele-tele.
Saya memiliki perspektif berbeda untuk menjawab ini. Jawaban semacam ini "apa lagi yang bisa saya lakukan untuk menghindarinya? "
Ketika bekerja di berbagai lapisan , misalnya dalam aplikasi MVC, pengontrol membutuhkan layanan untuk memanggil operasi bisnis. Dalam skenario seperti itu, Dependency Injection Container dapat digunakan untuk menginisialisasi layanan untuk menghindari NullReferenceException . Jadi itu berarti Anda tidak perlu khawatir tentang memeriksa null dan cukup memanggil layanan dari controller seolah-olah mereka akan selalu tersedia (dan diinisialisasi) baik sebagai singleton atau prototipe.
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();
}
}
Untuk masalah "apa yang harus saya lakukan" , ada banyak jawaban.
Cara yang lebih "formal" untuk mencegah kondisi kesalahan seperti itu saat mengembangkan adalah menerapkan desain dengan kontrak dalam kode Anda. Ini berarti Anda perlu mengatur kelas invarian , dan / atau bahkan fungsi / metode prasyarat dan postkondisi pada sistem Anda, sambil mengembangkan.
Singkatnya, invarian kelas memastikan bahwa akan ada beberapa kendala di kelas Anda yang tidak akan dilanggar dalam penggunaan normal (dan oleh karena itu, kelas tidak akan mendapatkan dalam keadaan tidak konsisten). Prasyarat berarti bahwa data yang diberikan sebagai input ke fungsi / metode harus mengikuti beberapa batasan yang ditetapkan dan tidak pernah melanggarnya, dan postkondisi berarti bahwa output fungsi / metode harus mengikuti batasan yang ditetapkan lagi tanpa pernah melanggarnya. Kondisi kontrak tidak boleh dilanggar selama pelaksanaan program bebas bug, oleh karena itu desain berdasarkan kontrak diperiksa dalam praktiknya dalam mode debug, sementara dinonaktifkan dalam rilis , untuk memaksimalkan kinerja sistem yang dikembangkan.
Dengan cara ini, Anda dapat menghindari NullReferenceException
kasus-kasus yang merupakan hasil pelanggaran terhadap batasan yang ditetapkan. Misalnya, jika Anda menggunakan properti objek X
di kelas dan kemudian mencoba memanggil salah satu metode dan X
memiliki nilai nol, maka ini akan mengarah ke NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Tetapi jika Anda menetapkan "properti X tidak boleh memiliki nilai nol" sebagai prasyarat metode, maka Anda dapat mencegah skenario yang dijelaskan sebelumnya:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Untuk alasan ini, proyek Kontrak Kode ada untuk aplikasi .NET.
Atau, desain berdasarkan kontrak dapat diterapkan dengan menggunakan asersi .
UPDATE: Perlu disebutkan bahwa istilah ini diciptakan oleh Bertrand Meyer sehubungan dengan desainnya bahasa pemrograman Eiffel .
A NullReferenceException
dilemparkan ketika kita mencoba mengakses Properti dari objek nol atau ketika nilai string menjadi kosong dan kita mencoba mengakses metode string.
Sebagai contoh:
Ketika metode string dari string kosong diakses:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Ketika properti objek null diakses:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
tidak akan melempar pengecualian referensi nol. Ini mewakili string aktual, meskipun yang kosong (yaitu ""
). Karena ini memiliki objek untuk dipanggil ToLower()
, tidak masuk akal untuk melempar pengecualian referensi nol di sana.
TL; DR: Coba gunakan Html.Partial
sebagai gantiRenderpage
Saya mendapatkan Object reference not set to an instance of an object
ketika saya mencoba menyajikan Tampilan dalam Tampilan dengan mengirimkannya Model, seperti ini:
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Debugging menunjukkan model itu Null di dalam MyOtherView. Sampai saya mengubahnya menjadi:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Dan itu berhasil.
Selain itu, alasan saya tidak harus Html.Partial
memulainya adalah karena Visual Studio kadang-kadang melempar garis berlekuk-galat di bawah Html.Partial
jika itu di dalam foreach
loop yang dibangun secara berbeda , meskipun itu sebenarnya bukan kesalahan:
@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>
Tapi saya bisa menjalankan aplikasi tanpa masalah dengan "kesalahan" ini. Saya dapat menyingkirkan kesalahan dengan mengubah struktur foreach
loop agar terlihat seperti ini:
@foreach(var M in MyEntities){
...
}
Meskipun saya merasa itu karena Visual Studio salah membaca tanda kurung dan kurung.
Html.Partial
, bukan@Html.Partial
Null
), jadi saya tahu kesalahannya adalah bagaimana saya mengirim Model.
Apa yang bisa kamu lakukan?
Ada banyak jawaban bagus di sini yang menjelaskan referensi nol dan bagaimana men-debug-nya. Tetapi ada sangat sedikit tentang bagaimana mencegah masalah atau setidaknya membuatnya lebih mudah untuk ditangkap.
Periksa argumen
Sebagai contoh, metode dapat memeriksa argumen yang berbeda untuk melihat apakah mereka nol dan melempar ArgumentNullException
, pengecualian yang jelas dibuat untuk tujuan yang tepat ini.
Konstruktor untuk ArgumentNullException
even mengambil nama parameter dan pesan sebagai argumen sehingga Anda dapat memberi tahu pengembang apa masalahnya.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Gunakan Alat
Ada juga beberapa perpustakaan yang dapat membantu. "Resharper" misalnya dapat memberi Anda peringatan saat Anda menulis kode, terutama jika Anda menggunakan atributnya: NotNullAttribute
Ada "Kontrak Kode Microsoft" di mana Anda menggunakan sintaksis seperti Contract.Requires(obj != null)
yang memberi Anda runtime dan kompilasi memeriksa: Memperkenalkan Kontrak Kode .
Ada juga "PostSharp" yang akan memungkinkan Anda untuk hanya menggunakan atribut seperti ini:
public void DoSometing([NotNull] obj)
Dengan melakukan itu dan menjadikan PostSharp bagian dari proses build Anda obj
akan diperiksa nol pada saat runtime. Lihat: cek kosong PostSharp
Solusi Kode Biasa
Atau Anda selalu bisa mengkode pendekatan Anda sendiri menggunakan kode lama polos. Misalnya di sini adalah struct yang dapat Anda gunakan untuk menangkap referensi nol. Ini dimodelkan setelah konsep yang sama dengan 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 };
}
}
Anda akan menggunakan sangat mirip dengan cara yang sama Anda akan gunakan Nullable<T>
, kecuali dengan tujuan mencapai yang sebaliknya - untuk tidak mengizinkan null
. Berikut ini beberapa contohnya:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
secara implisit dilemparkan ke dan dari T
sehingga Anda dapat menggunakannya di mana saja Anda membutuhkannya. Misalnya, Anda bisa meneruskan Person
objek ke metode yang mengambil NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Seperti yang Anda lihat di atas sebagai nullable, Anda akan mengakses nilai yang mendasarinya melalui Value
properti. Atau, Anda dapat menggunakan gips eksplisit atau implisit, Anda dapat melihat contoh dengan nilai pengembalian di bawah:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Atau Anda bahkan dapat menggunakannya ketika metode baru saja kembali T
(dalam hal ini Person
) dengan melakukan gips. Misalnya, kode berikut hanya akan seperti kode di atas:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Gabungkan dengan Extension
Kombinasikan NotNull<T>
dengan metode ekstensi dan Anda dapat membahas lebih banyak situasi. Berikut adalah contoh tampilan metode ekstensi:
[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;
}
}
Dan ini adalah contoh bagaimana itu bisa digunakan:
var person = GetPerson().NotNull();
GitHub
Untuk referensi Anda, saya membuat kode di atas tersedia di GitHub, Anda dapat menemukannya di:
https://github.com/luisperezphd/NotNull
Fitur Bahasa Terkait
C # 6.0 memperkenalkan "operator null-kondisional" yang sedikit membantu. Dengan fitur ini, Anda dapat mereferensikan objek bersarang dan jika salah satunya adalah null
keseluruhan ekspresi yang dikembalikan null
.
Ini mengurangi jumlah cek nol yang harus Anda lakukan dalam beberapa kasus. Sintaksnya adalah meletakkan tanda tanya sebelum setiap titik. Ambil kode berikut sebagai contoh:
var address = country?.State?.County?.City;
Bayangkan itu country
adalah objek tipe Country
yang memiliki properti yang disebut State
dan sebagainya. Jika country
, State
, County
, atau City
yang null
kemudian address will be
nol . Therefore you only have to check whether
alamat is
null`.
Ini fitur hebat, tetapi memberi Anda lebih sedikit informasi. Itu tidak membuatnya jelas yang mana dari 4 adalah nol.
Built-in seperti Nullable?
C # memiliki singkatan yang bagus untuk Nullable<T>
, Anda dapat membuat sesuatu nullable dengan meletakkan tanda tanya setelah tipe seperti itu int?
.
Akan lebih baik jika C # memiliki sesuatu seperti NotNull<T>
struct di atas dan memiliki singkatan yang sama, mungkin tanda seru sehingga Anda bisa menulis sesuatu seperti (!): public void WriteName(Person! person)
.
Menariknya, tidak ada jawaban di halaman ini yang menyebutkan dua sisi tepi, harap tidak ada yang keberatan jika saya menambahkannya:
Kamus umum di .NET tidak aman untuk thread dan kadang - kadang mereka melempar NullReference
atau bahkan (lebih sering) aKeyNotFoundException
ketika Anda mencoba mengakses kunci dari dua utas secara bersamaan. Pengecualian cukup menyesatkan dalam kasus ini.
Jika NullReferenceException
dilemparkan oleh unsafe
kode, Anda mungkin melihat variabel pointer Anda, dan memeriksanyaIntPtr.Zero
atau sesuatu. Yang merupakan hal yang sama ("pengecualian pointer nol"), tetapi dalam kode yang tidak aman, variabel sering dilemparkan ke tipe-nilai / array, dll., Dan Anda membenturkan kepala ke dinding, bertanya-tanya bagaimana tipe-nilai dapat membuang ini pengecualian.
(Alasan lain untuk tidak menggunakan kode tidak aman kecuali Anda memerlukannya, by the way)
null
dengan caranya?
Anda dapat memperbaiki NullReferenceException dengan cara yang bersih menggunakan Null-conditional Operator di c # 6 dan menulis lebih sedikit kode untuk menangani cek nol.
Ini digunakan untuk menguji nol sebelum melakukan operasi akses anggota (?) Atau indeks (? [).
Contoh
var name = p?.Spouse?.FirstName;
setara dengan:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
Hasilnya adalah bahwa nama akan menjadi nol ketika p adalah nol atau ketika p. Pasangan adalah nol.
Jika tidak, nama variabel akan diberi nilai p.Spouse.FirstName.
Untuk lebih jelasnya: Operator Bersyarat
Baris kesalahan "Referensi objek tidak disetel ke instance objek." Menyatakan bahwa Anda belum menetapkan objek instance ke referensi objek dan Anda masih mengakses properies / metode objek itu.
misalnya: katakanlah Anda memiliki kelas yang disebut myClass dan mengandung satu properti prop1.
public Class myClass
{
public int prop1 {get;set;}
}
Sekarang Anda mengakses prop1 ini di beberapa kelas lain seperti di bawah ini:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
baris di atas melempar kesalahan karena referensi kelas myClass dideklarasikan tetapi tidak instantiated atau turunan objek tidak ditugaskan ke referecne dari kelas itu.
Untuk memperbaiki ini, Anda harus instantiate (menetapkan objek untuk referensi kelas itu).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
Referensi NullReferenceException atau Obyek yang tidak disetel ke instance objek terjadi ketika objek kelas yang Anda coba gunakan tidak instantiated. Sebagai contoh:
Asumsikan bahwa Anda memiliki kelas bernama Siswa.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Sekarang, pertimbangkan kelas lain tempat Anda mencoba mengambil nama lengkap siswa.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Seperti terlihat pada kode di atas, pernyataan Siswa s - hanya menyatakan variabel tipe Siswa, perhatikan bahwa kelas Siswa tidak dipakai pada saat ini. Oleh karena itu, ketika pernyataan s.GetFullName () dijalankan, itu akan membuang NullReferenceException.
Nah, secara sederhana:
Anda mencoba mengakses objek yang tidak dibuat atau saat ini tidak ada dalam memori.
Jadi bagaimana cara mengatasinya:
Debug dan biarkan debugger istirahat ... Ini akan langsung membawa Anda ke variabel yang rusak ... Sekarang tugas Anda adalah hanya memperbaiki ini .. Menggunakan kata kunci baru di tempat yang tepat.
Jika itu disebabkan pada beberapa perintah database karena objek tidak ada maka yang perlu Anda lakukan adalah melakukan centang nol dan menanganinya:
if (i == null) {
// Handle this
}
Yang paling sulit .. jika GC mengumpulkan objek sudah ... Ini umumnya terjadi jika Anda mencoba untuk menemukan objek menggunakan string ... Artinya, menemukannya dengan nama objek maka dapat terjadi bahwa GC mungkin sudah membersihkannya ... Ini sulit ditemukan dan akan menjadi cukup masalah ... Cara yang lebih baik untuk mengatasi ini adalah melakukan pemeriksaan nol di mana pun diperlukan selama proses pengembangan. Ini akan menghemat banyak waktu.
Dengan mencari dengan nama saya maksudkan beberapa kerangka kerja memungkinkan Anda untuk FIndObjects menggunakan string dan kode mungkin terlihat seperti ini: FindObject ("ObjectName");
Secara harfiah cara termudah untuk memperbaiki NullReferenceExeption memiliki dua cara. Jika Anda memiliki GameObject misalnya dengan skrip yang dilampirkan dan variabel bernama rb (rigidbody) variabel ini akan mulai nol ketika Anda memulai permainan.
Inilah sebabnya mengapa Anda mendapatkan NullReferenceExeption karena komputer tidak memiliki data yang disimpan dalam variabel itu.
Saya akan menggunakan variabel RigidBody sebagai contoh.
Kami dapat menambahkan data dengan sangat mudah sebenarnya dalam beberapa cara:
rb = GetComponent<Rigidbody>();
Start()
atauAwake()
fungsi. rb = AddComponent<RigidBody>();
Catatan lebih lanjut: Jika Anda ingin kesatuan untuk menambahkan komponen ke objek Anda dan Anda mungkin lupa menambahkannya, Anda bisa mengetikkan di [RequireComponent(typeof(RigidBody))]
atas deklarasi kelas Anda (ruang di bawah semua usings Anda).
Nikmati dan bersenang-senang membuat game!
Jika kami mempertimbangkan skenario umum di mana pengecualian ini dapat dilempar, mengakses properti dengan objek di atas.
Ex:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
di sini, jika alamatnya nol, maka Anda akan mendapatkan NullReferenceException.
Jadi, sebagai praktik, kita harus selalu menggunakan cek kosong, sebelum mengakses properti di objek tersebut (khususnya dalam generik)
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Ini pada dasarnya adalah pengecualian referensi Null . Sebagai Microsoft menyatakan-
Pengecualian NullReferenceException dilemparkan ketika Anda mencoba mengakses anggota jenis yang nilainya nol.
Itu berarti jika ada anggota yang tidak memiliki nilai apa pun dan kami membuat anggota itu untuk melakukan tugas tertentu, maka sistem tidak diragukan lagi akan melemparkan pesan dan berkata-
"Hei, tunggu, anggota itu tidak memiliki nilai sehingga tidak bisa melakukan tugas yang kamu serahkan."
Pengecualian itu sendiri mengatakan bahwa sesuatu sedang dirujuk tetapi nilainya tidak ditetapkan. Jadi ini menunjukkan bahwa itu hanya terjadi saat menggunakan tipe referensi karena tipe Value tidak dapat dibatalkan.
NullReferenceException tidak akan terjadi jika kita menggunakan anggota tipe Nilai.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Kode di atas menunjukkan string sederhana yang ditugaskan dengan null nilai .
Sekarang, ketika saya mencoba untuk mencetak panjang string str , saya mendapatkan pengecualian yang tidak tertangani dari tipe 'System.NullReferenceException' terjadi pesan karena anggota str menunjuk ke nol dan tidak mungkin ada panjang nol.
' NullReferenceException ' juga terjadi ketika kita lupa untuk instantiate jenis referensi.
Misalkan saya memiliki metode kelas dan anggota di dalamnya. Saya belum membuat kelas saya tetapi hanya memberi nama kelas saya. Sekarang jika saya mencoba menggunakan metode ini, kompiler akan melemparkan kesalahan atau mengeluarkan peringatan (tergantung pada kompiler).
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");
}
}
Kompiler untuk kode di atas menimbulkan kesalahan bahwa variabel obj tidak ditetapkan yang menandakan bahwa variabel kami memiliki nilai nol atau tidak sama sekali. Kompiler untuk kode di atas menimbulkan kesalahan bahwa variabel obj tidak ditetapkan yang menandakan bahwa variabel kami memiliki nilai nol atau tidak sama sekali.
NullReferenceException muncul karena kesalahan kami karena tidak memeriksa nilai objek. Kami sering membiarkan nilai objek tidak dicentang dalam pengembangan kode.
Itu juga muncul ketika kita lupa untuk instantiate objek kita. Menggunakan metode, properti, koleksi dll. Yang dapat mengembalikan atau menetapkan nilai nol juga bisa menjadi penyebab pengecualian ini.
Ada berbagai cara dan metode untuk menghindari pengecualian terkenal ini:
Pemeriksaan Eksplisit: Kita harus mematuhi tradisi untuk memeriksa objek, properti, metode, array, dan koleksi apakah itu nol. Ini dapat dengan mudah diimplementasikan menggunakan pernyataan kondisional seperti if-else if-else dll.
Penanganan pengecualian: Salah satu cara penting untuk mengelola pengecualian ini. Dengan menggunakan blok coba-tangkap-akhirnya yang sederhana, kita dapat mengontrol pengecualian ini dan juga menyimpan lognya. Ini bisa sangat berguna ketika aplikasi Anda sedang dalam tahap produksi.
Operator kosong: Operator penggabungan nol dan operator kondisional nol juga dapat digunakan dengan praktis saat menetapkan nilai ke objek, variabel, properti, dan bidang.
Debugger: Untuk pengembang, kami memiliki senjata besar untuk debugging bersama kami. Jika kita menghadapi NullReferenceException selama pengembangan wajah kita dapat menggunakan debugger untuk sampai ke sumber pengecualian.
Metode bawaan: Metode sistem seperti GetValueOrDefault (), IsNullOrWhiteSpace () dan IsNullorEmpty () memeriksa nulls dan menetapkan nilai default jika ada nilai nol.
Ada banyak jawaban bagus di sini. Anda juga dapat memeriksa deskripsi yang lebih rinci dengan contoh di blog saya .
Semoga ini bisa membantu juga!
Jika seseorang mendapatkan pesan ini selama menyimpan atau mengkompilasi build, tutup saja semua file dan kemudian buka file apa saja untuk dikompilasi dan disimpan.
Bagi saya alasannya adalah bahwa saya telah mengganti nama file dan file lama masih terbuka.