Pertanyaan Apa itu NullReferenceException, dan bagaimana cara memperbaikinya?


Saya memiliki beberapa kode dan ketika dijalankan, itu melempar a NullReferenceException, mengatakan:

Referensi objek tidak disetel ke instance objek.

Apa artinya ini, dan apa yang dapat saya lakukan untuk memperbaiki kesalahan ini?


1878


asal


Jawaban:


Apa penyebabnya?

Intinya

Anda mencoba menggunakan sesuatu itu null (atau Nothing di VB.NET). Ini berarti Anda mengaturnya null, atau Anda tidak pernah mengaturnya untuk apa pun.

Seperti yang lainnya, null dilewatkan. Jika memang null  di metode "A", bisa jadi metode yang "B" lewat a null  untuk metode "A".

null dapat memiliki arti yang berbeda:

  1. Variabel objek yang tidak diinisialisasi dan karenanya menunjukkan apa-apa. Dalam hal ini, jika Anda mengakses properti atau metode objek tersebut, itu menyebabkan a NullReferenceException.
  2. Pengembangnya menggunakan null sengaja menunjukkan tidak ada nilai berarti yang tersedia. Perhatikan bahwa C # memiliki konsep tipe data nullable untuk variabel (seperti tabel database dapat memiliki bidang yang dapat dihapus) - Anda dapat menetapkan null kepada mereka untuk menunjukkan tidak ada nilai yang tersimpan di dalamnya, misalnya int? a = null; di mana tanda tanya menunjukkan itu diizinkan untuk menyimpan nol dalam variabel a. Anda dapat memeriksa apakah dengan if (a.HasValue) {...} atau dengan if (a==null) {...}. Variabel nullable, suka a contoh ini, memungkinkan untuk mengakses nilai melalui a.Value secara eksplisit, atau hanya melalui normal a.
    Catatan yang mengaksesnya via a.Value melempar sebuah InvalidOperationException bukannya a NullReferenceException jika a aku s null - Anda harus melakukan pemeriksaan terlebih dahulu, yaitu jika Anda memiliki variabel lain yang dapat ditunda int b; maka Anda harus melakukan tugas-tugas seperti if (a.HasValue) { b = a.Value; } atau lebih pendek if (a != null) { b = a; }.

Sisa dari artikel ini masuk ke lebih detail dan menunjukkan kesalahan yang sering dibuat oleh banyak programmer yang dapat mengarah pada NullReferenceException.

Lebih spesifik

Runtime melontarkan a NullReferenceException  selalu berarti hal yang sama: Anda mencoba menggunakan referensi, dan referensi tidak diinisialisasi (atau itu sekali diinisialisasi, tetapi adalah tidak lagi diinisialisasi).

Ini berarti rujukannya null, dan Anda tidak dapat mengakses anggota (seperti metode) melalui a null referensi. Kasus paling sederhana:

string foo = null;
foo.ToUpper();

Ini akan melempar a NullReferenceException di baris kedua karena Anda tidak dapat memanggil metode instance ToUpper() pada suatu string referensi menunjuk ke null.

Debugging

Bagaimana Anda menemukan sumber a NullReferenceException? Selain melihat pengecualian itu sendiri, yang akan dilempar tepat di lokasi di mana itu terjadi, aturan umum debugging dalam Visual Studio berlaku: tempat breakpoint strategis dan periksa variabel Anda, baik dengan mengarahkan mouse di atas nama mereka, membuka jendela Watch (Cepat) atau menggunakan berbagai panel debug seperti Locals dan Autos.

Jika Anda ingin mencari tahu di mana referensi tersebut atau tidak diatur, klik kanan namanya dan pilih "Temukan Semua Referensi". Anda kemudian dapat menempatkan breakpoint di setiap lokasi yang ditemukan dan menjalankan program Anda dengan debugger terlampir. Setiap kali debugger rusak pada breakpoint seperti itu, Anda perlu menentukan apakah Anda mengharapkan referensi menjadi tidak null, periksa variabel dan dan verifikasi bahwa itu menunjuk ke sebuah instance ketika Anda mengharapkannya.

Dengan mengikuti alur program dengan cara ini, Anda dapat menemukan lokasi tempat instance tidak boleh kosong, dan mengapa tidak diatur dengan benar.

Contoh

Beberapa skenario umum di mana pengecualian dapat dilemparkan:

Umum

ref1.ref2.ref3.member

Jika ref1 atau ref2 atau ref3 adalah null, maka Anda akan mendapatkan NullReferenceException. Jika Anda ingin memecahkan masalah, maka cari tahu mana yang null dengan menulis ulang ekspresi ke persamaan sederhananya:

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

Secara khusus, dalam HttpContext.Current.User.Identity.Name, yang HttpContext.Current bisa nihil, atau User properti bisa null, atau Identity properti bisa nihil.

Tidak langsung

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 null anak (Orang), Anda dapat menginisialisasi dalam konstruktor objek induk (Buku).

Inisialisasi Objek Bersarang

Hal yang sama berlaku untuk penginisialisasi objek bertingkat:

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

Ini diterjemahkan menjadi

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

Selagi new kata kunci digunakan, itu hanya menciptakan contoh baru Book, tetapi bukan contoh baru dari Person, sehingga Author properti itu masih null.

Inisialisasi Koleksi Bersarang

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

Inisialisasi koleksi bertingkat 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" });

Itu new Person hanya membuat turunan dari Person, tetapi Books koleksi masih null. Sintaksis pengumpul koleksi tidak membuat koleksi untuk p1.Books, itu hanya diterjemahkan ke p1.Books.Add(...) pernyataan.

Array

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

Elemen Array

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.

Jagged Arrays

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.

Koleksi / Daftar / Kamus

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

Variabel Range (Tidak Langsung / Ditangguhkan)

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.

Acara

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

Konvensi Penamaan Buruk:

Jika Anda menamai bidang berbeda dari penduduk setempat, Anda mungkin telah menyadari bahwa Anda tidak pernah menginisialisasi bidang tersebut.

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

Ini dapat diselesaikan dengan mengikuti konvensi ke awalan dengan garis bawah:

private Customer _customer;

Halaman ASP.NET Siklus hidup:

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

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

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

ASP.NET Session Values

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

Model tampilan kosong ASP.NET MVC

Jika pengecualian terjadi saat mereferensikan properti @Model dalam pandangan ASP.NET MVC, Anda perlu memahami bahwa Model diatur dalam metode tindakan Anda, ketika Anda return pemandangan. Ketika Anda mengembalikan model kosong (atau properti model) dari pengontrol Anda, pengecualian terjadi ketika tampilan 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 Control Creation Order and Events

Kontrol WPF dibuat selama panggilan ke InitializeComponent dalam urutan mereka muncul di pohon visual. SEBUAH NullReferenceException akan dibangkitkan dalam kasus kontrol yang dibuat awal dengan pengendali event, dll., kebakaran itu selama InitializeComponent yang mereferensi kontrol yang dibuat akhir.

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>

Sini comboBox1 dibuat sebelumnya label1. Jika comboBox1_SelectionChanged mencoba mereferensikan `label1, itu belum akan dibuat.

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

Mengubah urutan deklarasi di XAML (yaitu, daftar label1 sebelum comboBox1, mengabaikan masalah filosofi desain, setidaknya akan menyelesaikan NullReferenceException sini.

Transmisikan dengan as

var myThing = someObject as Thing;

Ini tidak membuang InvalidCastException tetapi mengembalikan a null ketika para pemain gagal (dan ketika someObject itu sendiri tidak ada). Jadi sadari itu.

LINQ FirstOrDefault () dan SingleOrDefault ()

Versi polos First() dan Single() membuang pengecualian ketika tidak ada apa-apa. Versi "OrDefault" mengembalikan null dalam kasus itu. Jadi sadari itu.

untuk setiap

foreach melempar ketika Anda mencoba untuk iterasi koleksi null. Biasanya disebabkan oleh hal yang tidak terduga null hasil 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 membuang jika node tidak ditemukan tetapi debug awal menunjukkan bahwa semua properti valid:

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

Cara untuk Hindari

Periksa secara eksplisit null dan mengabaikan nilai nol.

Jika Anda mengharapkan referensi kadang-kadang menjadi nol, Anda dapat memeriksanya null sebelum mengakses anggota instance:

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

Periksa secara eksplisit null dan berikan nilai default.

Metode panggilan yang Anda harapkan untuk mengembalikan instance dapat kembali null, misalnya ketika objek yang dicari tidak dapat ditemukan. Anda dapat memilih untuk mengembalikan nilai default saat ini terjadi:

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

Periksa secara eksplisit null dari pemanggilan metode dan melempar pengecualian khusus.

Anda juga dapat membuang 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;
}

Menggunakan Debug.Assert jika tidak ada nilai null, untuk menangkap masalah lebih awal dari pengecualian terjadi.

Ketika Anda tahu selama pengembangan bahwa metode mungkin bisa, tetapi tidak pernah harus kembali null, Kamu dapat memakai 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.
}

Padahal cek ini tidak akan berakhir di versi rilis Anda, menyebabkannya melempar NullReferenceException lagi kapan book == null saat runtime dalam mode rilis.

Menggunakan GetValueOrDefault() untuk tipe nilai nullable untuk memberikan nilai default ketika mereka 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

Gunakan operator penggabungan nol: ?? [C #] atau If() [VB].

Singkatan untuk memberikan nilai default ketika a 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;
}

Gunakan operator kondisi null: ?. atau ?[x] untuk array (tersedia di C # 6 dan VB.NET 14):

Ini juga kadang disebut sebagai navigasi yang aman atau operator Elvis (setelah bentuknya). Jika ekspresi di sisi kiri operator adalah null, maka sisi kanan tidak akan dievaluasi, dan null dikembalikan sebagai gantinya. Itu berarti kasus seperti ini:

var title = person.Title.ToUpper();

Jika orang tersebut tidak memiliki judul, ini akan melemparkan pengecualian karena mencoba menelepon ToUpper pada properti dengan nilai nol.

Dalam C # 5 dan di bawah, ini dapat dijaga dengan:

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

Sekarang variabel judul akan menjadi null daripada melempar pengecualian. C # 6 memperkenalkan sintaks yang lebih pendek untuk ini:

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

Ini akan menghasilkan variabel judul sedang null, dan panggilan ke ToUpper tidak dibuat jika person.Title aku s null.

Tentu saja kamu masih harus memeriksa title untuk null atau menggunakan operator kondisi null 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 yang bisa Anda gunakan ?[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 adalah null, ekspresi mengembalikan null dan Anda dapat dengan aman memeriksanya. Jika berisi array, ia akan melakukan hal yang sama seperti: elem = myIntArray[i]; dan mengembalikan ith elemen.

Teknik khusus untuk debugging dan memperbaiki null derefs dalam iterator

C # mendukung "blok iterator" (disebut "generator" dalam beberapa bahasa populer lainnya). Pengecualian dereferensi Null dapat menjadi sangat rumit untuk melakukan debug pada 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 hasil dalam null kemudian 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 sebenarnya tidak menjalankan sampai foreach! Panggilan ke GetFrobs hanya mengembalikan objek yang ketika iterasi akan menjalankan blok iterator.

Dengan menulis cek null seperti ini Anda mencegah dereferensi null, tetapi Anda memindahkan pengecualian argumen null ke titik perulangan, bukan ke titik panggilan, dan itu adalah sangat membingungkan untuk melakukan 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();
}

Artinya, membuat metode pembantu pribadi yang memiliki logika blok iterator, dan metode permukaan publik yang melakukan pemeriksaan null dan mengembalikan iterator. Sekarang kapan GetFrobs disebut, pemeriksaan null segera terjadi, dan kemudian GetFrobsForReal mengeksekusi ketika urutan iterasi.

Jika Anda memeriksa sumber referensi untuk LINQ ke Objek Anda akan melihat bahwa teknik ini digunakan di seluruh. Ini sedikit lebih kikuk untuk ditulis, tapi itu membuat kesalahan nulling debugging jauh lebih mudah. Optimalkan kode Anda untuk kenyamanan si penelepon, bukan kenyamanan si penulis.

Catatan tentang dereferences null dalam kode yang tidak aman

C # memiliki mode "tidak aman" yang, seperti namanya, sangat berbahaya karena mekanisme keselamatan normal yang memberikan keamanan memori dan keselamatan jenis tidak diberlakukan. Anda tidak boleh menulis kode yang tidak aman kecuali Anda memiliki pemahaman yang mendalam dan mendalam tentang cara kerja memori.

Dalam mode tidak aman, Anda harus menyadari dua fakta penting:

  • dereferencing null penunjuk menghasilkan pengecualian yang sama seperti dereferencing null referensi
  • dereferencing penunjuk non-null tidak valid bisa menghasilkan pengecualian itu dalam beberapa keadaan

Untuk memahami mengapa itu, ini membantu untuk memahami bagaimana. NET menghasilkan pengecualian dereferensi nol di tempat pertama. (Detail ini berlaku untuk .NET yang berjalan di Windows; sistem operasi lain menggunakan mekanisme yang serupa.)

Memori virtual pada Windows; setiap proses mendapatkan ruang memori virtual dari banyak "halaman" memori yang dilacak oleh sistem operasi. Setiap halaman memori memiliki bendera yang ditetapkan di atasnya yang menentukan bagaimana ia dapat digunakan: baca dari, ditulis ke, dieksekusi, dan seterusnya. Itu terendah Halaman ditandai sebagai "menghasilkan kesalahan jika pernah digunakan dengan cara apa pun".

Baik pointer null dan referensi null di C # secara internal direpresentasikan sebagai angka nol, dan sehingga setiap upaya untuk mengalihkannya ke penyimpanan memori yang sesuai menyebabkan sistem operasi menghasilkan kesalahan. NET runtime. Kemudian mendeteksi kesalahan ini dan mengubahnya menjadi pengecualian dereference null.

Itu sebabnya dereferencing baik pointer null dan referensi null menghasilkan pengecualian yang sama.

Bagaimana dengan poin kedua? Dereferencing apa saja Penunjuk tidak valid yang jatuh di halaman terendah dari memori virtual menyebabkan kesalahan sistem operasi yang sama, dan dengan demikian pengecualian yang sama.

Mengapa ini masuk akal? Yah, misalkan kita memiliki struct yang berisi dua int, dan pointer unmanaged sama dengan null. Jika kita mencoba untuk dereference int kedua di struct, CLR tidak akan mencoba mengakses penyimpanan di lokasi nol; itu akan mengakses penyimpanan di lokasi empat. Tapi secara logis ini adalah dereference nol karena kita menuju ke alamat itu melalui null.

Jika Anda bekerja dengan kode tidak aman dan Anda mendapatkan null dereference exception, ketahuilah bahwa penunjuk yang menyinggung tidak perlu null. Ini dapat berupa lokasi apa pun di halaman terendah, dan pengecualian ini akan dihasilkan.


2107



Pengecualian NullReference - Visual Basic

Itu NullReference Exception untuk Dasar visual tidak berbeda dari yang di C #. Setelah semua, mereka berdua melaporkan pengecualian yang sama didefinisikan dalam. NET Framework yang mereka gunakan. Penyebab unik untuk Visual Basic jarang (mungkin hanya satu).

Jawaban ini akan menggunakan istilah Visual Basic, sintaksis, dan konteks. Contoh yang digunakan berasal dari sejumlah besar pertanyaan Stack Overflow yang lalu. Ini untuk memaksimalkan relevansi dengan menggunakan macam-macam situasi yang sering terlihat di pos. Penjelasan lebih sedikit juga disediakan bagi mereka yang mungkin membutuhkannya. Contoh yang serupa dengan Anda adalah sangat kemungkinan tercantum di sini.

catatan:

  1. Ini adalah konsep berbasis: tidak ada kode untuk Anda tempelkan ke proyek Anda. Ini dimaksudkan untuk membantu Anda memahami apa yang menyebabkan suatu NullReferenceException (NRE), cara menemukannya, cara memperbaikinya, dan cara menghindarinya. Suatu NRE dapat disebabkan banyak cara jadi ini tidak mungkin menjadi satu-satunya pertemuan Anda.
  2. Contoh-contoh (dari posting Stack Overflow) tidak selalu menunjukkan cara terbaik untuk melakukan sesuatu di tempat pertama.
  3. Biasanya, obat yang paling sederhana digunakan.

Makna Dasar

Pesan "Objek tidak disetel ke instance Objek" berarti Anda mencoba menggunakan objek yang belum diinisialisasi. Ini bermuara pada salah satu dari ini:

  • Kode Anda dideklarasikan variabel objek, tetapi tidak menginisialisasi itu (buat instance atau 'memberi contoh' saya t)
  • Sesuatu yang diasumsikan kode Anda akan menginisialisasi objek, tidak
  • Mungkin, kode lain terlalu dini membatalkan objek yang masih digunakan

Menemukan Penyebabnya

Karena masalahnya adalah referensi obyek yang Nothing, jawabannya adalah memeriksa mereka untuk mencari tahu yang mana. Kemudian tentukan mengapa tidak diinisialisasi. Pegang mouse di atas berbagai variabel dan Visual Studio (VS) akan menunjukkan nilai-nilai mereka - pelakunya akan Nothing.

IDE debug display

Anda juga harus menghapus semua blok Coba / Tangkap dari kode yang relevan, terutama yang tidak ada di dalam blok Tangkapan. Ini akan menyebabkan kode Anda macet ketika mencoba untuk menggunakan objek yang Nothing. Ini yang kamu inginkan karena itu akan mengidentifikasi yang tepat lokasi masalah, dan memungkinkan Anda untuk mengidentifikasi objek yang menyebabkannya.

SEBUAH MsgBox di Catch yang ditampilkan Error while... akan sedikit membantu. Metode ini juga mengarah ke sangat buruk Pertanyaan Stack Overflow, karena Anda tidak dapat menggambarkan pengecualian yang sebenarnya, objek yang terlibat atau bahkan baris kode di mana itu terjadi.

Anda juga bisa menggunakan Locals Window (Debug -> Windows -> Warga) untuk memeriksa objek Anda.

Setelah Anda tahu apa dan di mana masalahnya, biasanya cukup mudah untuk memperbaikinya dan lebih cepat daripada memposting pertanyaan baru.

Lihat juga:

Contoh dan Remedies

Obyek Kelas / Membuat Instance

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

Masalahnya adalah Dim tidak membuat CashRegister obyek; itu hanya mendeklarasikan variabel bernama reg Tipe itu. Mendeklarasikan sebuah variabel objek dan menciptakan sebuah contoh adalah dua hal yang berbeda.

Memperbaiki

Itu New operator sering dapat digunakan untuk membuat instance saat Anda mendeklarasikannya:

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

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

Ketika itu hanya tepat untuk membuat contoh nanti:

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

catatan: Tidak menggunakan 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 lokal variabel, reg, yang hanya ada dalam konteks itu (sub). Itu reg variabel dengan level modul Scope yang akan Anda gunakan di tempat lain tetap ada Nothing.

Hilang New operator adalah penyebab # 1 dari NullReference Exceptions terlihat dalam pertanyaan Stack Overflow yang ditinjau.

Visual Basic mencoba untuk membuat proses jelas berulang kali digunakan New: Menggunakan New Operator membuat a baru objek dan panggilan Sub New - konstruktor - di mana objek Anda dapat melakukan inisialisasi lainnya.

Agar jelas, Dim (atau Private) saja menyatakan variabel dan Type. Itu Cakupan dari variabel - apakah itu ada untuk seluruh modul / kelas atau lokal ke prosedur - ditentukan oleh dimana itu dinyatakan. Private | Friend | Public mendefinisikan tingkat akses, bukan Cakupan.

Untuk informasi lebih lanjut, lihat:


Array

Array juga harus dipakai:

Private arr as String()

Array ini hanya telah dideklarasikan, tidak dibuat. Ada beberapa cara untuk menginisialisasi larik:

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, yang As <Type> dan New elemen bersifat 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. Deklarasi tingkat kelas / modul masih membutuhkan 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 Foobenda-benda di dalamnya belum.

Memperbaiki

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

Menggunakan sebuah List(Of T) akan membuatnya cukup 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:


Daftar dan Koleksi

Koleksi .NET (yang memiliki banyak ragam - Daftar, Kamus, dll.) Juga harus dipakai atau dibuat.

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

Anda mendapatkan pengecualian yang sama untuk alasan yang sama - myList hanya dinyatakan, 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

Prosedurnya akan menghasilkan NRE, karena barList hanya dinyatakan, tidak dipakai. Membuat instance dari Foo tidak akan juga membuat turunan internal barList. Itu 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 salah:

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.


Objek Penyedia Data

Bekerja dengan database menyajikan banyak peluang untuk NullReference karena bisa ada banyak objek (Command, Connection, Transaction, Dataset, DataTable, DataRows....) digunakan sekaligus. catatan: Tidak masalah penyedia data yang Anda gunakan - MySQL, SQL Server, OleDB, dll - konsep adalah 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 ditetapkan, tetapi sebuah instance tidak pernah dibuat. Itu DataAdapter akan mengisi yang sudah ada DataSet, jangan buat satu. Dalam hal ini, sejak ds adalah variabel lokal, IDE memperingatkan Anda bahwa ini mungkin terjadi:

img

Ketika dideklarasikan sebagai variabel tingkat modul / kelas, seperti yang tampaknya terjadi con, compiler tidak dapat mengetahui apakah objek itu dibuat oleh prosedur upstream. Jangan abaikan peringatan.

Memperbaiki

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)

Salah ketik adalah masalah di sini: Employees vs Employee. Tidak ada DataTable bernama "Karyawan" dibuat, jadi a NullReferenceException hasil mencoba mengaksesnya. Masalah potensial lainnya adalah dengan asumsi akan ada Items yang mungkin tidak begitu ketika SQL termasuk klausa WHERE.

Memperbaiki

Karena ini menggunakan satu tabel, menggunakan Tables(0) akan menghindari kesalahan ejaan. Meneliti 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 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

Itu DataAdapter akan menyediakan TableNames seperti yang ditunjukkan pada contoh sebelumnya, tetapi tidak menguraikan nama dari tabel SQL atau database. Hasil dari, ds.Tables("TICKET_RESERVATION") referensi tabel tidak ada.

Itu Memperbaiki adalah sama, referensi tabel dengan indeks:

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

Lihat juga Kelas DataTable.


Jalur Obyek / Bersarang

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

Kode hanya menguji Items sementara keduanya myFoo dan Bar mungkin juga Tidak ada. Itu memperbaiki adalah 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 begitu yang pertama False kondisi ditemui. Ini memungkinkan kode untuk 'mengebor' dengan aman ke objek satu tingkat pada suatu waktu, mengevaluasi myFoo.Bar hanya setelah (dan jika) myFoo bertekad untuk berlaku. Objek rantai atau jalur bisa menjadi sangat panjang ketika mengkodekan objek yang kompleks:

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

Tidak mungkin untuk mereferensikan apa pun 'hilir' a null obyek. Ini juga berlaku untuk kontrol:

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

Sini, myWebBrowser atau Document bisa menjadi Tidak ada atau formfld1 elemen mungkin tidak ada.


Kontrol UI

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

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.

Memperbaiki

Validasi data sebelum menggunakannya (juga digunakan 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...


Bentuk Visual Basic

Public Class Form1

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

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

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

Ini adalah cara umum untuk mendapatkan NRE. Dalam C #, tergantung pada bagaimana ia dikodekan, IDE akan melaporkannya Controls tidak ada dalam konteks saat ini, atau "tidak dapat merujuk anggota non-statis". Jadi, sampai taraf tertentu, ini adalah situasi VB-only. Ini juga kompleks karena dapat menyebabkan kegagalan kaskade.

Array dan koleksi tidak dapat diinisialisasi dengan cara ini. Kode inisialisasi ini akan berjalan sebelum konstruktor menciptakan Form atau Controls. Hasil dari:

  • Daftar dan Koleksi hanya akan kosong
  • Array akan berisi lima elemen dari Tidak ada
  • Itu somevar tugas akan menghasilkan NRE langsung karena Tidak ada yang tidak punya .Text milik

Mereferensikan elemen array nantinya akan menghasilkan NRE. Jika Anda melakukan ini Form_Load, karena bug yang aneh, IDE mungkin tidak laporkan pengecualian saat itu terjadi. Pengecualian akan muncul kemudian saat kode Anda mencoba menggunakan larik. Ini "pengecualian diam" rinci dalam posting ini. Untuk tujuan kita, kuncinya adalah ketika sesuatu yang malapetaka terjadi saat membuat formulir (Sub New atau Form Load event), 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, banyak hal lainnya dapat dibiarkan terinisialisasi.

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 semua dan semua referensi kontrol dan komponen yang menjadikan 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 untuk menyatakan wadah di tingkat formulir, tapi menginisialisasi mereka dalam bentuk event handler ketika kontrol melakukan ada. Ini bisa dilakukan di 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 penampung (seperti a GroupBox atau Panel) tidak akan ditemukan di Me.Controls; mereka akan berada dalam koleksi Kontrol Panel atau Kotak Grup tersebut. Kontrol tidak akan dikembalikan ketika nama kontrol salah eja ("TeStBox2"). Dalam beberapa kasus, Nothing lagi-lagi akan disimpan dalam elemen-elemen array dan NRE akan dihasilkan ketika Anda mencoba untuk mereferensikannya.

Ini harus mudah ditemukan sekarang karena Anda tahu apa yang Anda cari: VS shows you the error of your ways

"Button2" berada di a Panel

Memperbaiki

Daripada referensi tidak langsung dengan menggunakan nama form's Controlskoleksi, 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...})

Fungsi Tidak Mengembalikan

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 a NullReferenceException dapat mengakibatkan'. Anda dapat menekan peringatan, dengan mengganti Exit Function dengan Return Nothing, tetapi itu tidak memecahkan masalah. Apa pun yang mencoba menggunakan kembali kapan someCondition = False akan menghasilkan NRE:

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

Memperbaiki

Menggantikan Exit Function dalam fungsi dengan Return bList. Mengembalikan an kosong  List tidak sama dengan kembali Nothing. Jika ada kemungkinan objek yang dikembalikan bisa Nothing, uji sebelum menggunakannya:

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

Try / Catch yang diimplementasikan dengan buruk

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 yang tidak dibuat seperti yang diharapkan, tetapi juga menunjukkan kegunaan counter dari kosong Catch.

Ada koma tambahan dalam SQL (setelah 'mailaddress') yang menghasilkan pengecualian pada .ExecuteReader. Setelah Catch tidak melakukan apa-apa, Finally mencoba untuk melakukan pembersihan, tetapi karena Anda tidak bisa Close null DataReader objek, merek baru NullReferenceException hasil.

Sebuah kosong Catch blok adalah tempat bermain iblis. OP ini bingung mengapa dia mendapatkan NRE di internet Finally blok. Dalam situasi lain, kosong Catch dapat menghasilkan sesuatu yang lebih jauh ke hilir yang rusak dan menyebabkan Anda menghabiskan waktu untuk melihat hal-hal yang salah di tempat yang salah untuk masalah tersebut. ("Pengecualian diam" yang dijelaskan di atas memberikan nilai hiburan yang sama.)

Memperbaiki

Jangan menggunakan blok Try / Catch kosong - biarkan kode crash 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.


DBNull tidak sama dengan Tidak Ada

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

Itu IsDBNull fungsi digunakan untuk menguji apakah a nilai sama System.DBNull: Dari MSDN:

Nilai System.DBNull menunjukkan bahwa Objek menunjukkan data yang hilang atau tidak ada. DBNull tidak sama dengan Tidak ada, yang menunjukkan bahwa variabel belum diinisialisasi.

Memperbaiki

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

Seperti sebelumnya, Anda dapat menguji apa pun, lalu 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, yaitu Nothing untuk tipe referensi dan tidak pernah DBNull:

If getFoo IsNot Nothing Then...

Kontrol

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 GroupBox), kemudian chk tidak akan ada dan mencoba mereferensikan properti apa pun akan menghasilkan pengecualian.

Memperbaiki

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

The DataGridView

DGV memiliki beberapa quirks 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 punya AutoGenerateColumns = True, itu akan membuat kolom, tetapi itu tidak menamai mereka, sehingga kode di atas gagal ketika referensi mereka dengan nama.

Memperbaiki

Beri nama kolom secara manual, atau referensi berdasarkan indeks:

dgvBooks.Columns(0).Visible = True

Contoh 2 - Waspadai NewRow

xlWorkSheet = xlWorkBook.Sheets("sheet1")

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

Ketika Anda DataGridView punya AllowUserToAddRows sebagai True (default), yang Cells di baris kosong / baru di bagian bawah semuanya akan berisi Nothing. Sebagian besar upaya untuk menggunakan konten (misalnya, ToString) akan menghasilkan NRE.

Memperbaiki

Gunakan For/Each loop 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, ubah jumlah baris atau gunakan Exit For kapan IsNewRow adalah benar.


My.Settings (StringCollection)

Dalam keadaan tertentu, mencoba menggunakan item dari My.Settings yang mana StringCollection dapat menghasilkan NullReference saat pertama kali Anda menggunakannya. Solusinya sama, tetapi tidak jelas. Mempertimbangkan:

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

Karena VB mengelola Pengaturan untuk Anda, wajar untuk mengharapkannya menginisialisasi koleksi. Ini akan, tetapi hanya jika Anda sebelumnya telah menambahkan entri awal ke koleksi (di editor Pengaturan). Karena koleksi tersebut (rupanya) diinisialisasi ketika item ditambahkan, itu tetap Nothing ketika tidak ada item di editor Pengaturan untuk ditambahkan.

Memperbaiki

Inisialisasi koleksi pengaturan dalam formulir Load pengendali event, bila diperlukan:

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

Biasanya, itu Settings koleksi hanya perlu diinisialisasi saat pertama kali aplikasi berjalan. Obat alternatif adalah menambahkan nilai awal ke koleksi Anda di Proyek -> Pengaturan | FooBars, simpan proyek, lalu hapus nilai palsu.


Poin Kunci

Anda mungkin lupa New operator.

atau

Sesuatu yang Anda anggap akan bekerja dengan sempurna untuk mengembalikan objek yang diinisialisasi ke kode Anda, tidak.

Jangan abaikan peringatan kompilator (pernah) dan gunakan Option Strict On (selalu).


MSDN NullReference Exception


273



Skenario lain adalah ketika Anda membuang objek null menjadi jenis nilai. Misalnya, kode di bawah ini:

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

Itu akan melempar a NullReferenceException pada pemain. Tampaknya cukup jelas dalam contoh di atas, tetapi ini bisa terjadi pada skenario yang lebih rumit "akhir-mengikat" di mana objek nol telah dikembalikan dari beberapa kode yang tidak Anda miliki, dan gips misalnya dihasilkan oleh beberapa sistem otomatis.

Salah satu contoh dari ini adalah fragmen mengikat ASP.NET sederhana ini dengan kontrol Kalender:

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

Sini, SelectedDate sebenarnya adalah properti - dari DateTime jenis - dari Calendar Jenis Kontrol Web, dan pengikatan bisa mengembalikan sesuatu yang tidak benar dengan sempurna. Generator ASP.NET implisit akan membuat potongan kode yang akan setara dengan kode cast di atas. Dan ini akan meningkatkan NullReferenceException yang cukup sulit untuk spot, karena terletak pada kode yang dihasilkan ASP.NET yang mengkompilasi ...


217



Ini berarti bahwa variabel tersebut tidak menunjukkan apa-apa. Saya bisa menghasilkan ini seperti:

SqlConnection connection = null;
connection.Open();

Itu akan membuang kesalahan karena ketika saya mendeklarasikan variabel "connection", itu tidak menunjuk apa-apa. Ketika saya mencoba untuk memanggil anggota"Open", tidak ada referensi untuk menyelesaikannya, dan itu akan membuang kesalahan.

Untuk menghindari kesalahan ini:

  1. Selalu menginisialisasi objek Anda sebelum Anda mencoba melakukan apa pun dengan mereka.
  2. Jika Anda tidak yakin apakah objeknya null, periksa dengan object == null.

Alat Resharper JetBrains akan mengidentifikasi setiap tempat dalam kode Anda yang memiliki kemungkinan kesalahan referensi null, memungkinkan Anda untuk memasukkan cek null. Kesalahan ini adalah sumber bug nomor satu, IMHO.


146



Ini berarti kode Anda menggunakan variabel referensi objek yang disetel ke null (yaitu tidak merujuk contoh objek yang sebenarnya).

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
}

135



Sadarilah bahwa apa pun skenarionya, penyebabnya selalu sama di .NET:

Anda mencoba menggunakan variabel referensi yang nilainya Nothing/null. Kapan nilainya Nothing/null untuk variabel referensi, itu berarti tidak benar-benar memegang referensi ke sebuah instance dari 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 menjadi Nothing/null untukmu.


90



Contoh pengecualian ini 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
} 

NET runtime. Akan membuang NullReferenceException ketika Anda mencoba untuk melakukan tindakan pada sesuatu yang belum dipakai instantiated yaitu kode di atas.

Dibandingkan dengan ArgumentNullException yang biasanya dilemparkan sebagai ukuran defensif jika metode mengharapkan bahwa apa yang sedang diteruskan ke itu tidak nol.

Informasi lebih lanjut ada di C # NullReferenceException dan Parameter Null.


76



Jika Anda belum menginisialisasi tipe referensi, dan Anda ingin mengatur atau membaca salah satu propertinya, ia akan melempar a NullReferenceException.

Contoh:

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

Anda dapat dengan mudah menghindari ini dengan memeriksa apakah variabelnya tidak null:

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

Untuk memahami sepenuhnya mengapa NullReferenceException dilempar, penting untuk mengetahui perbedaannya jenis nilai dan tipe referensi.

Jadi, jika Anda berurusan dengan jenis nilai, NullReferenceExceptions bisa tidak terjadi. Padahal Anda perlu tetap waspada saat berhadapan tipe referensi!

Hanya tipe referensi, seperti namanya, dapat menyimpan referensi atau menunjuk secara harfiah ke tidak ada (atau 'null'). Sedangkan jenis nilai selalu mengandung nilai.

Jenis referensi (yang ini harus diperiksa):

  • dinamis
  • obyek
  • tali

Jenis nilai (Anda cukup mengabaikan yang ini):

  • Tipe numerik
  • Tipe Integral
  • Jenis titik-mengambang
  • desimal
  • bool
  • Struct didefinisikan pengguna

72



Lain halnya di mana NullReferenceExceptions bisa terjadi adalah (salah) penggunaan 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

Sini, Book dan Car adalah jenis yang tidak kompatibel; Sebuah Car tidak dapat dikonversi / dibuang ke a Book. Ketika pemain ini gagal, as kembali null. Menggunakan mybook setelah ini menyebabkan a NullReferenceException.

Secara umum, Anda harus menggunakan gips atau as, sebagai berikut:

Jika Anda mengharapkan jenis konversi untuk selalu berhasil (mis. Anda tahu apa objek harus lebih dulu dari waktu), maka Anda harus menggunakan gips:

ComicBook cb = (ComicBook)specificBook;

Jika Anda tidak yakin dengan tipenya, tetapi Anda menginginkannya mencoba untuk menggunakannya sebagai tipe tertentu, kemudian gunakan as:

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

65