Soru NullReferenceException nedir ve nasıl düzeltebilirim?


Bazı kodlarım var ve ne zaman idam ederse, atar NullReferenceExceptionsöyleyerek:

Nesne referansı bir nesnenin örneğine atanmadı.

Bu ne anlama geliyor ve bu hatayı düzeltmek için ne yapabilirim?


1878


Menşei


VS 2017'deki istisna yardımcısı, bu istisnanın nedenini teşhis etmede daha yararlı olacaktır - blogs.msdn.microsoft.com/visualstudio/2016/11/28/... altında Yeni İstisna Yardımcı. - Zev Spitz
Biz sadece "nesne başlatılmamış" deriz? Yani bir değişken beyanınız varsa: SomeClass myVariable; Bu, SomeClass'a referansla myVariable'ı oluşturacaktır, ancak Başlatmadı ve null'a eşit olacaktır. SomeClass myVariable = new SomeClass () yaparak sınıf başlatmayı çağırmalısınız. Veya, başka bir değişkene bir başvuru dönen eğer:) (SomeClass myVariable = anotherVariableDeclared; - Arvin Amir
@ Arvin ne hakkında? MfClass - John Saunders
Sevgili geleceğin ziyaretçileri, bu soruya verilen cevaplar aynı şekilde ArgumentNullException. Sorunuz, bunun bir kopyası olarak kapatıldıysa ve bir ANE yaşamanız varsa, lütfen hata ayıklama ve sorununuzu gidermek için yanıtlardaki yönergeleri izleyin. - Will
@will ANE sadece bir null parametresi olarak geçirilirse gerçekleşmelidir. Bir ANE sorusu, bunun bir kopyası olarak kapatılmışsa bir örnek verebilir misiniz? - John Saunders


Cevaplar:


Sebebi nedir?

Alt çizgi

Bir şey kullanmaya çalışıyorsunuz. null (veya Nothing VB.NET'te). Bu, ya nullya da asla hiç bir şeye koymazsın.

Başka her şey gibi null etrafında geçer. Eğer öyleyse null  içinde yöntem "A", bu yöntem "B" olabilir bir olabilir null  için yöntem "A".

null farklı anlamları olabilir:

  1. Nesne değişkenleri başlatılmamış ve dolayısıyla hiçbir şeye işaret etmeyin. Bu durumda, bu tür nesnelerin özelliklerine veya yöntemlerine erişirseniz, NullReferenceException.
  2. Geliştirici kullanma null Mevcut anlamlı bir değer olmadığını belirtmek isteyerek. C # 'nun değişkenler için null yapılabilen veri tipleri (veritabanı tabloları null alanlara sahip olabilir) kavramına sahip olduğunu unutmayın. null örneğin içinde kayıtlı bir değer olmadığını belirtmek için int? a = null; soru işareti, null değişkeninde saklanmasına izin verildiğini gösterir. a. Bunu ile kontrol edebilirsiniz if (a.HasValue) {...} veya ile if (a==null) {...}. Nullabilir değişkenler gibi a bu örnek, üzerinden değere erişime izin ver a.Value açıkça veya normal yoldan a.
    Not üzerinden erişerek a.Value bir atar InvalidOperationException yerine NullReferenceException Eğer a olduğu null - kontrolü daha önce yapmalısınız, yani başka bir null olmayan değişkeniniz varsa int b; o zaman atamalar gibi if (a.HasValue) { b = a.Value; } veya daha kısa if (a != null) { b = a; }.

Bu makalenin geri kalanı daha ayrıntılı bir şekilde ortaya çıkıyor ve çoğu programcının sık sık karşılaşabileceği hataları gösteriyor. NullReferenceException.

Daha spesifik olarak

Çalışma zamanı NullReferenceException  her zaman aynı şeyi ifade eder: bir referans kullanmaya çalışıyorsunuz ve referans başlatılmıyor (veya bir Zamanlar başlatıldı, ama Artık başlatıldı).

Bu, referansın anlamı nullve üyelere (yöntemler gibi) bir null referans. En basit durum:

string foo = null;
foo.ToUpper();

Bu bir atar NullReferenceException ikinci satırda örnek yöntemini arayaamadığınız için ToUpper() üzerinde string referans gösteren null.

Hata ayıklama

Kaynağını nasıl buluyorsunuz NullReferenceException? Visual Studio'da hata ayıklamanın genel kuralları, tam olarak nerede oluştuğu yere atılacak olan istisnanın kendisine bakmak yerine, stratejik ayrılma noktaları ve değişkenlerinizi inceleyinya fareyi isimleri üzerinde gezdirerek, bir (Hızlı) Watch penceresini açarak veya Locals ve Autos gibi çeşitli hata ayıklama panellerini kullanarak.

Referansın nerede olduğunu veya ayarlanmadığını öğrenmek istiyorsanız, ismine sağ tıklayın ve "Tüm Referansları Bul" u seçin. Daha sonra bulunan her yere bir kesme noktası yerleştirebilir ve programınızı hata ayıklayıcısını ekleyerek çalıştırabilirsiniz. Hata ayıklayıcının böyle bir kesme noktasında kırıldığı her defasında, başvurunun boş olmadığından emin olup olmadığınızı, değişkeni incelemenizi ve beklediğiniz zaman örneğini gösterip göstermediğini doğrulamanız gerekir.

Program akışını bu şekilde takip ederek, örneğin null olmaması gereken konumu ve neden uygun şekilde ayarlanmadığını bulabilirsiniz.

Örnekler

Özel durumun atılabileceği bazı yaygın senaryolar:

genel

ref1.ref2.ref3.member

Ref1 veya ref2 veya ref3 boşsa, o zaman bir NullReferenceException. Sorunu çözmek istiyorsanız, ifadeyi daha basit eşdeğerine yeniden yazarak null olanı bulun:

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

Özellikle, içinde HttpContext.Current.User.Identity.Name, HttpContext.Current boş olabilir veya User özellik boş olabilir veya Identity özellik boş olabilir.

Dolaylı

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

Çocuğun (Kişi) null başvurusundan kaçınmak istiyorsanız, bunu ana (Kitap) nesnesinin yapıcısında başlatabilirsiniz.

Yuvalanmış Nesne Başlatıcıları

Aynı, iç içe geçmiş nesne başlatıcıları için de geçerlidir:

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

Bu çevirir

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

İken new anahtar kelime kullanılır, yalnızca yeni bir örnek oluşturur Bookama yeni bir örnek değil Person, Böylece Author mülkiyet hala null.

Yuvalanmış Koleksiyon Başlatıcıları

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

İç içe geçmiş koleksiyon başlatıcıları aynı davranır:

Person p1 = new Person {
    Books = {
        new Book { Title = "Title1" },
        new Book { Title = "Title2" },
    }
};

Bu çevirir

Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });

new Person sadece bir örnek oluşturur Person, ama Books koleksiyon hala null. Koleksiyon başlatıcı sözdizimi bir koleksiyon oluşturmuyor için p1.Books, sadece çevirir p1.Books.Add(...) ifadeleri.

Dizi

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

Dizi Öğeleri

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 Diziler

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.

Toplama / Liste / Sözlük

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

Aralık Değişkeni (Dolaylı / Ertelenmiş)

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.

Olaylar

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

Kötü Adlandırma Kuralları:

Alanlardan farklı bir alan adı verdiyseniz, alanı hiç başlatmamış olduğunuzu fark etmiş olabilirsiniz.

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

Bu alt çizgi ile önek alanlarına kongre izleyerek çözülebilir:

private Customer _customer;

ASP.NET Sayfa Yaşam döngüsü:

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 Oturum Değerleri

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

ASP.NET MVC boş görünüm modelleri

Bir özelliğe başvururken istisna oluşursa @Model bir ASP.NET MVC görünümünde, bunu anlamak gerekir Model eylem yönteminize girer, ne zaman return manzara. Denetleyicinizden boş bir modeli (veya model özelliğini) döndürdüğünüzde, görünümler erişime eriştiğinde istisna oluşur:

// 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 Oluşturma Düzeni ve Olaylar

WPF kontrolleri çağrı sırasında oluşturulur InitializeComponent sırayla görsel ağaçta görünürler. bir NullReferenceException Olay sırasında ortaya çıkan olay denetleyicileri vb. ile önceden oluşturulmuş kontrollerde ortaya çıkar. InitializeComponent Geç oluşturulan kontroller referans.

Örneğin :

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

İşte comboBox1 daha önce oluşturuldu label1. Eğer comboBox1_SelectionChanged etiket1'e başvurmaya çalışır, henüz oluşturulmayacaktır.

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

XAML'deki beyanların sırasını değiştirme (ör. Listeleme label1 önce comboBox1Tasarım felsefesinin önemini göz ardı ederek, en azından NullReferenceException İşte.

İle Cast as

var myThing = someObject as Thing;

Bu InvalidCastException atar, ancak bir null döküm başarısız olduğunda (ve bazı nedenler boştur ise). Bunun farkında ol.

LINQ FirstOrDefault () ve SingleOrDefault ()

Düz versiyonlar First() ve Single() Hiçbir şey olmadığında istisnalar atmak. Bu durumda "OrDefault" sürümleri null değerini döndürür. Bunun farkında ol.

her biri için

foreach boş koleksiyonunu yinelemeye çalıştığınızda atar. Genellikle beklenmedik neden olur null koleksiyonları döndüren yöntemlerden kaynaklanır.

 List<int> list = null;    
 foreach(var v in list) { } // exception

Daha gerçekçi örnek - XML ​​belgesindeki düğümleri seçin. Düğümler bulunmazsa, ancak ilk hata ayıklama, tüm özelliklerin geçerli olduğunu gösterirse atar.

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

Kaçınmanın Yolları

Açıkça kontrol edin null ve boş değerleri göz ardı eder.

Referansın bazen boş olmasını beklerseniz, bunun olup olmadığını kontrol edebilirsiniz. null örnek üyelerine erişmeden önce:

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

Açıkça kontrol edin null ve varsayılan bir değer sağlar.

Yöntemler geri dönmeyi beklediğiniz bir örneğe dönebilir nullörneğin aranan nesne bulunamıyorsa. Bu durumda varsayılan bir değer döndürmeyi seçebilirsiniz:

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

Açıkça kontrol edin null yöntem çağrıları ve özel bir istisna atmak.

Özel bir istisna da atayabilirsiniz, sadece çağrı kodunda onu yakalamak için:

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

kullanım Debug.Assert eğer bir değer asla olmamalı null, istisnadan daha önce sorunu yakalamak için oluşur.

Gelişim sırasında bildiğiniz gibi bir yöntem belki olabilir, ama asla dönmemelidir null, kullanabilirsiniz Debug.Assert() meydana geldiğinde mümkün olan en kısa zamanda kırmak için:

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

Bu kontrol rağmen sürüm oluşturma işleminde sona ermez, atmak için NullReferenceException tekrar ne zaman book == null serbest bırakma modunda çalışma zamanında.

kullanım GetValueOrDefault() NULL değerler için, olduklarında varsayılan bir değer sağlamak 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

Boş birleştirme işlecini kullanın: ?? [C #] veya If() [VB].

Ne zaman bir varsayılan değer sağlamak için null karşılaşıldı:

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

Boş durum operatörünü kullan: ?. veya ?[x] diziler için (C # 6 ve VB.NET 14'te kullanılabilir):

Bu aynı zamanda bazen güvenli navigasyon veya Elvis (şeklinin ardından) operatörü olarak da adlandırılır. Operatörün sol tarafındaki ifade boşsa, o zaman sağ taraf değerlendirilmeyecek ve null bunun yerine döndürülecektir. Bunun gibi durumlar anlamına gelir:

var title = person.Title.ToUpper();

Kişinin bir başlığı yoksa, bu çağrı yapmaya çalıştığı için bir istisna atar. ToUpper boş değerli bir mülkte.

C # 5 ve altında aşağıdakiler ile korunabilir:

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

Artık başlık değişkeni bir istisna atmak yerine boş olacaktır. C # 6, bunun için daha kısa bir sözdizimi sunar:

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

Bu, başlık değişkeninin nullve çağrı ToUpper eğer yapılmazsa person.Title olduğu null.

Tabiki sen yine kontrol etmek title null için boş sıfırlama işleciyle birlikte boş durum operatörünü kullanın (??) varsayılan değer sağlamak için:

// 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;

Aynı şekilde, diziler için kullanabilirsiniz ?[i] aşağıdaki gibi:

int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");

Bu, aşağıdakileri yapar: myIntArray boşsa, ifade null değerini döndürür ve güvenle kontrol edebilirsiniz. Bir dizi içeriyorsa, aynı şeyi yapar: elem = myIntArray[i]; ve i döndürürinci öğesi.

Yineleyicilerde null derefs hata ayıklama ve düzeltme için özel teknikler

C # "yineleyici blokları" destekler (diğer popüler dillerdeki "jeneratörler" olarak adlandırılır). Boştaki dereference istisnaları, ertelenmiş yürütme nedeniyle yineleyici bloklarda hata ayıklamak için özellikle zor olabilir:

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

Eğer whatever sonuç null sonra MakeFrob atar Şimdi, yapmanız gereken doğru şey şudur:

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

Bu neden yanlış? Yineleyici bloğu aslında olmadığından koşmak e kadar foreach! Çağrı GetFrobs sadece bir nesneyi döndürür tekrarlandığında yineleyici bloğunu çalıştıracaktır.

Bunun gibi boş bir onay yazarak boş değer engelini engellersiniz, ancak boş argüman istisnasını tekrarlamadeğil, aramak, ve bu hata ayıklamak için çok kafa karıştırıcı.

Doğru düzeltme:

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

Yani yineleyici blok mantığına sahip özel bir yardımcı yöntem ve boş nesneyi yineleyen ve yineleyiciyi döndüren bir genel yüzey yöntemi yapın. Şimdi ne zaman GetFrobs denir, null check derhal olur ve sonra GetFrobsForReal sıra yinelendiğinde yürütülür.

LINQ'un Objects için referans kaynağını incelerseniz, bu tekniğin her yerde kullanıldığını göreceksiniz. Yazmak biraz daha karmaşıktır, ancak hata ayıklama nullity hatalarını çok daha kolay hale getirir. Arayanın rahatlığı için kodunuzu optimize edin, yazarın rahatlığı için değil.

Güvenli olmayan koddaki null dereferences ile ilgili bir not

C #, adından da anlaşılacağı gibi, "güvenli olmayan" bir moda sahiptir, çünkü bellek güvenliği ve tip güvenliği sağlayan normal güvenlik mekanizmaları zorlanmaz. Belleğin nasıl çalıştığına dair kapsamlı ve derin bir anlayışa sahip değilseniz, güvenli olmayan kod yazmamalısınız..

Güvenli olmayan modda, iki önemli gerçeğin farkında olmalısınız:

  • dereferencing boş Işaretçi dereferencing ile aynı istisnayı üretir null referans
  • geçersiz bir boş olmayan işaretçiyi dereferencing kutu bu istisnayı üretmek bazı durumlarda

Bunun nedenini anlamak için, ilk olarak .NET'in null dereference istisnalarını nasıl ürettiğini anlamaya yardımcı olur. (Bu ayrıntılar, Windows'da çalışan .NET için geçerlidir; diğer işletim sistemleri benzer mekanizmaları kullanır.)

Bellek Windows'da sanallaştırılmıştır; Her işlem, işletim sistemi tarafından izlenen birçok "sayfa" hafızasının sanal bir belleğini alır. Her bir bellek sayfası üzerinde nasıl kullanılacağını belirleyen bayraklar bulunur: okuma, yazma, yürütme vb. en düşük sayfa "herhangi bir şekilde kullanılmışsa bir hata üret" olarak işaretlenir.

Hem bir boş gösterici hem de C # 'deki boş bir referans, sıfır olarak dahili olarak temsil edilir ve dolayısıyla, karşılık gelen bellek depolamasına ayıklama girişimi, işletim sisteminin bir hata üretmesine neden olur. .NET çalışma zamanı daha sonra bu hatayı algılar ve null dereference özel durumuna döndürür.

Bu nedenle, hem boş gösterici hem de boş bir referansın kaldırılması aynı istisnayı üretir.

İkinci noktadan ne haber? dereferencing herhangi Sanal belleğin en alt sayfasında yer alan geçersiz işaretçi aynı işletim sistemi hatasına ve dolayısıyla aynı istisnaa neden olur.

Bu neden mantıklı? Sanırım iki noktadan oluşan bir yapımız ve null'a eşit bir yönetilmeyen işaretçi var. Yapıdaki ikinci int'yi ayırmaya çalışırsak, CLR depolamaya sıfır konumunda erişmeye çalışmaz; Depodaki dördüncü konuma erişecek. Ama mantıklı olarak bu bir null dereferanstır çünkü biz bu adrese ulaşıyoruz üzerinden boş.

Güvenli olmayan bir kodla çalışıyorsanız ve boş bir kural dışı durum istisnası alıyorsanız, yalnızca sorun gideren işaretçinin null olması gerekmediğini unutmayın. En düşük sayfada herhangi bir yer olabilir ve bu istisna oluşturulacaktır.


2111



Belki bu bir aptal yorum ama bu sorunu önlemek için ilk ve en iyi yolu, nesneyi başlatmak için olurdu? Benim için bu hata oluşursa, genellikle dizi elemanı gibi bir şeyi başlatmayı unuttum çünkü. Nesneyi null olarak tanımlamak ve sonra başvurmak çok daha az yaygın olduğunu düşünüyorum. Belki de açıklamaya bitişik her problemi çözmenin yolunu verebiliriz. Hala iyi bir yazı. - JPK
Ya bir nesne yoksa, bir yöntem veya özellikten dönüş değeri ne olursa? - John Saunders
Kitap / yazar örneği biraz tuhaf… Bu nasıl derleniyor? İntellisense bile nasıl çalışır? Bu ne demek ben computar ile iyi değilim ... - Will
@Will: Son düzenleme yardımımı mı yapıyor? Değilse, lütfen sorun olarak gördükleriniz hakkında daha açık olun. - John Saunders
@JohnSaunders Oh, hayır, üzgünüm, bunun nesne başlatıcısı sürümünü kastediyorum. new Book { Author = { Age = 45 } }; İçsel başlatma bile nasıl ... İçsel initin işe yarayacağı bir durum düşünemiyorum, yine de derler ve akıl yürütür ... Yapılar için bir şey yok mu? - Will


NullReference İstisnası - Visual Basic

NullReference Exception için Visual Basic içindekilerden farklı değil C #. Sonuçta, ikisi de, her ikisi de kullandıkları .NET Framework'te tanımlanan aynı özel durumu bildiriyorlar. Visual Basic'e özgü nedenler nadirdir (belki de yalnızca bir tanesi).

Bu cevap, Visual Basic terimlerini, sözdizimini ve bağlamı kullanacaktır. Kullanılan örnekler, geçmişte çok sayıda Yığın Taşması ile ilgili sorulardan gelmektedir. Bu, kullanarak alaka düzeyini en üst düzeye çıkarmaktır. çeşit Mesajlarda sık görülen durumlar. İhtiyacı olanlar için biraz daha fazla açıklama da sağlanıyor. Size benzeyen bir örnek çok büyük olasılıkla burada listelenir.

Not:

  1. Bu konsept tabanlı: projenize yapıştırmanız için bir kod yok. Neye sebep olduğunu anlamanıza yardımcı olmak için tasarlanmıştır. NullReferenceException (NRE), nasıl bulunur, nasıl düzeltilir ve nasıl önlenir. Bir NRE birçok yönden kaynaklanabilir, bu nedenle bu sizin tek karşılaşmanızın olması muhtemel değildir.
  2. Örnekler (Yığın Taşma mesajlarından) her zaman bir şey yapmanın en iyi yolunu her zaman göstermez.
  3. Tipik olarak, en basit çözüm kullanılır.

Temel anlamı

Mesaj "Nesne bir nesne örneğine ayarlanmadı" başlatılmamış bir nesneyi kullanmaya çalıştığınız anlamına gelir. Bu şunlardan birine doğru kayıyor:

  • Senin kodun beyan bir nesne değişkeni, ama yoktu başlatmak o (bir örnek oluşturmak veya 'örneğini' o)
  • Kodunuzun bir nesneyi başlatacağı bir şey,
  • Muhtemelen, diğer kod hala kullanımda olan bir nesneyi zamanından önce geçersiz kılmıştır.

Nedeni Bulmak

Sorun, bir nesne referansı olduğundan NothingCevap, hangisini bulmak için onları incelemektir. Sonra neden başlatılmamış olduğunu belirleyin. Çeşitli değişkenler üzerinde fareyi tutun ve Visual Studio (VS) kendi değerlerini gösterir - suçlu Nothing.

IDE debug display

Ayrıca, herhangi bir Try / Catch bloklarını ilgili koddan çıkarmalısınız, özellikle de Catch bloğunda hiçbir şey olmayanlar. Bu, bir nesne kullanmaya çalışırken kodunuzun çökmesine neden olur. Nothing. Senin istediğin bu çünkü kesin olarak tanımlayacak yer Sorunun sebebi ve ona neden olan nesneyi tanımlamanıza izin verir.

bir MsgBox hangi Catch görüntüler Error while... küçük yardım olacak. Bu yöntem aynı zamanda çok kötü Yığın Taşması soruları, çünkü gerçek istisnayı, söz konusu nesneyi veya hatta kod satırını tanımlayamazsınız.

Ayrıca kullanabilirsiniz Locals Window (Hata ayıklama -> Windows -> Yerel) Nesnelerinizi incelemek.

Sorunun ne olduğunu ve nerede olduğunu öğrendikten sonra, yeni bir soru yayınlamaktan genellikle düzeltmek ve daha hızlıdır.

Ayrıca bakınız:

Örnekler ve Telafiler

Sınıf Nesneleri / Bir Örnek Oluşturma

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

Problem şu Dim bir CashRegister oluşturmuyor nesne; sadece adlandırılmış bir değişken bildirir reg Bu Türün. bildirilmesi bir nesne değişkeni ve bir örnek iki farklı şey vardır.

çare

New Operatör, bildirimde bulunduğunuzda örneği oluşturmak için sık sık kullanılabilir:

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

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

Örneği daha sonra oluşturmak için uygun olduğunda:

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

Not: Yapma kullanım Dim yine kurucu dahil bir prosedürde (Sub New):

Private reg As CashRegister
'...

Public Sub New()
   '...
   Dim reg As New CashRegister
End Sub

Bu bir yerel değişken, regSadece bu bağlamda var (alt). reg modül seviyesi ile değişken Scope başka her yerde kullanacağın kalır Nothing.

Eksik New operatör # 1 sebebi NullReference Exceptions Stack Overflow sorularında görüldü.

Visual Basic, işlemin tekrar tekrar kullanılmasını sağlar. New: Kullanmak New Operatör bir yeni nesne ve çağrılar Sub New - yapıcı - nesnenizin başka bir başlatmayı gerçekleştirebileceği yer.

Açık olmak gerekirse, Dim (veya Private) bir tek beyan bir değişken ve onun Type. kapsam değişkenin - tüm modül / sınıf için var mı yoksa bir prosedür için yerel mi olduğu - tarafından belirlenir nerede beyan edildi. Private | Friend | Public erişim seviyesini tanımlar, değil kapsam.

Daha fazla bilgi için bakınız:


Diziler

Diziler de örneklenmelidir:

Private arr as String()

Bu dizi sadece bildirilmemiş, oluşturulmamış. Bir diziyi başlatmanın birkaç yolu vardır:

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

Not: Bir literal kullanarak bir yerel diziyi başlatırken, VS 2010 ile başlayarak ve Option Infer, As <Type> ve New elemanlar isteğe bağlıdır:

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}

Veri Türü ve dizi boyutu, atanan verilerden çıkar. Sınıf / Modül seviyesi beyanları hala gerektirir As <Type> ile Option Strict:

Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}

Örnek: Sınıf nesnelerinin dizisi

Dim arrFoo(5) As Foo

For i As Integer = 0 To arrFoo.Count - 1
   arrFoo(i).Bar = i * 10       ' Exception
Next

Dizi oluşturuldu, ancak Fooiçindeki nesneler yok.

çare

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

Kullanma List(Of T) geçerli bir nesne olmayan bir öğeye sahip olmak oldukça zor olacaktır:

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

Daha fazla bilgi için bakınız:


Listeler ve Koleksiyonlar

.NET koleksiyonları (çok sayıda çeşit var - Listeler, Sözlük, vb) de örneklenmiş veya oluşturulmalıdır.

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

Aynı sebepten aynı istisnayı elde edersiniz - myList sadece beyan edildi, ancak örnek oluşturulmadı. Çare aynıdır:

myList = New List(Of String)

' Or create an instance when declared:
Private myList As New List(Of String)

Ortak bir gözetim, bir koleksiyonu kullanan bir sınıftır. 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

Her iki prosedür de bir NRE ile sonuçlanacaktır, çünkü barList sadece bildirilir, örneklendirilmez. Bir örnek oluşturma Foo dahili bir örneği de oluşturmaz barList. Bunu yapıcıda yapmanın amacı olabilir:

Public Sub New         ' Constructor
    ' Stuff to do when a new Foo is created...
    barList = New List(Of Bar)
End Sub

Daha önce olduğu gibi, bu yanlıştır:

Public Sub New()
    ' Creates another barList local to this procedure
     Dim barList As New List(Of Bar)
End Sub

Daha fazla bilgi için bakınız List(Of T) Sınıf.


Veri Sağlayıcı Nesneleri

Veritabanlarıyla çalışmak NullReference için birçok fırsat sunar çünkü birçok nesne olabilir (Command, Connection, Transaction, Dataset, DataTable, DataRows....) bir kerede kullanımda. Not: Hangi veri sağlayıcısını kullandığınız önemli değildir - MySQL, SQL Server, OleDB, vs. - kavramlar aynıdır.

örnek 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

Daha önce olduğu gibi ds Veri kümesi nesnesi bildirildi, ancak bir örnek oluşturulmadı. DataAdapter var olanı dolduracak DataSet, bir tane oluşturmayın. Bu durumda ds yerel bir değişkendir IDE sizi uyarıyor Bu olabilir:

img

Bir modül / sınıf düzeyi değişkeni olarak bildirildiğinde, con, derleyici nesnenin bir yukarı akış yordamı tarafından oluşturulduğunu bilemez. Uyarıları dikkate almayın.

çare

Dim ds As New DataSet

Örnek 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)

Yazım hatası burada bir sorun: Employees vs Employee. Yoktu DataTable "Çalışan" olarak adlandırıldı, böylece bir NullReferenceException sonuçlara erişmeye çalışıyor. Başka bir potansiyel sorun var olacağını varsayıyor Items SQL bir WHERE yan tümcesi içerdiğinde böyle olmayabilir.

çare

Bu, bir tabloyu kullandığından Tables(0) yazım hatalarından kaçınacaktır. incelenmesi Rows.Count ayrıca yardımcı olabilir:

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 sayısı dönen bir işlevdir Rows etkilenen, ayrıca test edilebilir:

If da.Fill(ds, "Employees") > 0 Then...

Örnek 3

Dim da As New OleDb.OleDbDataAdapter("SELECT TICKET.TICKET_NO,
        TICKET.CUSTOMER_ID, ... FROM TICKET_RESERVATION AS TICKET INNER JOIN
        FLIGHT_DETAILS AS FLIGHT ... WHERE [TICKET.TICKET_NO]= ...", con)
Dim ds As New DataSet
da.Fill(ds)

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

DataAdapter sağlayacak TableNames Önceki örnekte gösterildiği gibi, ancak SQL veya veritabanı tablosundan isimleri ayrıştırmaz. Sonuç olarak, ds.Tables("TICKET_RESERVATION") varolmayan bir tabloya başvurur.

çare aynıdır, tabloya göre indeksle:

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

Ayrıca bakınız DataTable sınıfı.


Nesne yolları / iç içe geçmiş

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

Kod sadece test ediliyor Items her ikisi de myFoo ve Bar Ayrıca hiçbir şey olmayabilir. çare nesnenin tüm zincirini veya yolunu tek tek test etmektir:

If (myFoo IsNot Nothing) AndAlso
    (myFoo.Bar IsNot Nothing) AndAlso
    (myFoo.Bar.Items IsNot Nothing) Then
    ....

AndAlso önemli. İlk testler ilk kez yapılmayacaktır. False durumla karşılaşılır. Bu, kodun bir kerede nesneye bir 'seviye' güvenli bir şekilde 'delinmesine' izin verir. myFoo.Bar sadece sonra (ve eğer) myFoo geçerli olduğu belirlenmiştir. Nesne zincirleri veya yolları, karmaşık nesneleri kodlarken oldukça uzun olabilir:

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

Bir şeyin 'aşağı akışına' referans vermek mümkün değildir. null nesne. Bu ayrıca kontroller için de geçerlidir:

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

İşte, myWebBrowser veya Document hiçbir şey ya da formfld1 öğe mevcut olmayabilir.


UI Denetimleri

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)

Diğer şeyler arasında, bu kod kullanıcının bir veya daha fazla UI denetiminde bir şey seçmemiş olabileceğini öngörmez. ListBox1.SelectedItem Iyi olabilir Nothing, yani ListBox1.SelectedItem.ToString bir NRE ile sonuçlanacaktır.

çare

Kullanmadan önce verileri doğrula (kullan Option Strict ve SQL parametreleri):

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

Alternatif olarak, kullanabilirsiniz (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Visual Basic Formları

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

Bu bir NRE almak için oldukça yaygın bir yoldur. C # 'de, nasıl kodlandığına bağlı olarak, IDE Controls geçerli bağlamda mevcut değil veya "statik olmayan üyeye başvuru yapamaz". Yani, bir dereceye kadar, bu sadece bir VB durumudur. Aynı zamanda karmaşıktır çünkü bir arıza kaskadına neden olabilir.

Diziler ve koleksiyonlar bu şekilde başlatılamaz. Bu başlatma kodu çalıştırılacak önce kurucu oluşturur Form ya da Controls. Sonuç olarak:

  • Listeler ve Koleksiyon sadece boş olacak
  • Dizi, Nothing'in beş unsurunu içerecek
  • somevar atama anında NRE ile sonuçlanacaktır çünkü hiçbir şey bir .Text özellik

Daha sonra dizi elemanlarına başvurmak bir NRE ile sonuçlanacaktır. Bunu yaparsan Form_Loadtek bir hatadan dolayı IDE olmayabilir gerçekleştiğinde istisnayı rapor et. İstisna açılır sonra kodunuz diziyi kullanmaya çalıştığında. Bu "sessiz istisna" bu yayında ayrıntılı. Bizim amacımız için anahtar, bir form yaratırken yıkıcı bir şey ortaya çıktığında (Sub New veya Form Load olayı), istisnalar bildirilmemiş olabilir, kod prosedürden çıkar ve sadece formu görüntüler.

Başka kodunuz olmadığından Sub New veya Form Load etkinlik NRE'den sonra çalışacak başka pek çok şey başlatılmamış bırakılabilir.

Sub Form_Load(..._
   '...
   Dim name As String = NameBoxes(2).Text        ' NRE
   ' ...
   ' More code (which will likely not be executed)
   ' ...
End Sub

Not Bu, aşağıdakileri yasadışı yapan tüm kontrol ve bileşen referansları için geçerlidir:

Public Class Form1

    Private myFiles() As String = Me.OpenFileDialog1.FileName & ...
    Private dbcon As String = OpenFileDialog1.FileName & ";Jet Oledb..."
    Private studentName As String = TextBox13.Text

Kısmi Çözüm

VB'nin bir uyarı vermediği merak ediliyor ama bildirmek kapları form düzeyinde, ama başlatmak kontroller yaparken onları form yük olay işleyicide yap var olmak. Bu yapılabilir Sub New senin kodun peşinde olduğu sürece InitializeComponent aramak:

' 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

Dizi kodu henüz ormanların dışında olmayabilir. Konteynır kontrolünde bulunan kontroller ( GroupBox veya Panel) bulunamadı Me.Controls; Bu Panelin veya GroupBox'un Kontroller koleksiyonunda olacaklar. Kontrol adı yanlış yazıldığında kontrol edilmeyecektir ("TeStBox2"). Bu gibi durumlarda, Nothing yine bu dizi elemanlarında saklanır ve referans göstermeye çalıştığınızda bir NRE ortaya çıkar.

Aradığınızı bildiğinizi şimdi bulmak kolay olmalı: VS shows you the error of your ways

"Button2" bir Panel

çare

Formu kullanarak isimle dolaylı referanslar yerine Controlstoplama, kontrol referansını kullanın:

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

İşlev Dönen Hiçbir Şey

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

Bu, IDE'nin sizi uyaracağı bir durumdur.tüm yollar bir değer döndürmez ve NullReferenceException sonuçlanabilir'. Uyarıyı değiştirerek iptal edebilirsiniz Exit Function ile Return Nothingama bu sorunu çözmez. Ne zaman geri dönüşü kullanmaya çalışan herhangi bir şey someCondition = False bir NRE ile sonuçlanacak:

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

çare

değiştirmek Exit Function işlevinde Return bList. Geri dönen boş  List geri dönen ile aynı değildir Nothing. Döndürülen bir nesnenin olabilme ihtimali varsa Nothingkullanmadan önce test edin:

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

Kötü Uygulanmış Try / Catch

Kötü bir şekilde uygulanan bir Try / Catch, sorunun nerede olduğunu gizleyebilir ve yeni olanlarla sonuçlanabilir:

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

Bu, beklendiği gibi oluşturulmayan bir nesnenin durumudur, ancak aynı zamanda boş bir sayacın kullanışlılığını da gösterir. Catch.

SQL'de ('mailaddress' sonra) bir istisna ile sonuçlanan ekstra bir virgül var. .ExecuteReader. Sonra Catch hiç birşey yapmıyor, Finally temizlemeyi deniyor, ama yapamayacağın için Close null DataReader nesne, yepyeni NullReferenceException Sonuçlar.

Boş Catch blok şeytanın oyun alanıdır. Bu OP, niçin NRE aldığına şaşırmıştı. Finally blok. Diğer durumlarda, boş Catch Başka bir şey daha fazla aşağı akışlı haywire gidiyor olabilir ve sorun için yanlış yere yanlış şeyler bakarak zaman harcamak neden olabilir. (Yukarıda açıklanan "sessiz istisna" aynı eğlence değerini sağlar.)

çare

Boş Try / Catch bloklarını kullanmayın - kodun çökmesine izin verin, böylece a) nedenini tanımlayın b) yeri belirleyin ve c) uygun bir çözüm uygulayın. Deneme / Yakalama blokları, bunları düzeltmek için benzersiz kalifiye kişilerden istisnaları gizlemeye yönelik değildir - geliştirici.


DBNull hiçbir şey ile aynı değil

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

IsDBNull fonksiyon test etmek için kullanılır eğer değer eşittir System.DBNull: MSDN'den:

System.DBNull değeri, nesnenin eksik veya var olmayan verileri temsil ettiğini gösterir. DBNull, bir değişkenin henüz başlatılmamış olduğunu belirten Hiçbir Şey ile aynı değildir.

çare

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

Daha önce olduğu gibi, Nothing için, ardından belirli bir değer için test edebilirsiniz:

If (row.Cells(0) IsNot Nothing) AndAlso (IsDBNull(row.Cells(0).Value) = False) Then

Örnek 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 ilk öğeyi veya varsayılan değeri döndürür. Nothing referans türleri için ve asla DBNull:

If getFoo IsNot Nothing Then...

Kontroller

Dim chk As CheckBox

chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
    Return chk
End If

Eğer bir CheckBox ile chkName bulunamadı (veya bir GroupBox), sonra chk Hiçbir şey olmayacak ve herhangi bir özelliğe başvurmaya çalışmak bir istisna ile sonuçlanacaktır.

çare

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

DataGridView

DGV periyodik olarak görülen birkaç tuhaflığa sahiptir:

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"

Eğer dgvBooks vardır AutoGenerateColumns = Truesütunları oluşturacak, ancak bunlara isim vermeyecek, bu nedenle yukarıdaki kod, adlarına göre başvurduğunda başarısız oluyor.

çare

Sütunları manuel olarak adlandırın veya dizine göre başvurun:

dgvBooks.Columns(0).Visible = True

Örnek 2 - NewRow'a dikkat edin

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

Senin ne zaman DataGridView vardır AllowUserToAddRows gibi True (varsayılan), Cells altta boş / yeni satırda hepsi içerecektir Nothing. İçeriği kullanmaya yönelik çoğu girişim (örneğin, ToString) bir NRE ile sonuçlanacaktır.

çare

Kullanın For/Each döngü ve test IsNewRow Bu son satır olup olmadığını belirlemek için özellik. Bu ister AllowUserToAddRows doğru ya da değil:

For Each r As DataGridViewRow in myDGV.Rows
    If r.IsNewRow = False Then
         ' ok to use this row

Eğer bir For n döngü, satır sayısını değiştirmek veya kullanmak Exit For ne zaman IsNewRow doğru.


My.Settings (StringCollection)

Belirli koşullar altında, bir öğeyi kullanmaya çalışmak My.Settings hangisi StringCollection İlk kez kullandığınızda NullReference ile sonuçlanabilir. Çözüm aynıdır, ancak açık değildir. Düşünmek:

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

VB sizin için Ayarları yönetiyor olduğundan, koleksiyonun başlatılmasını beklemek makul olacaktır. Ancak, ancak daha önce koleksiyona bir başlangıç ​​girdisi eklediyseniz (Ayarlar düzenleyicide). Bir öğe eklendiğinde koleksiyon (görünüşte) başlatıldığından beri, Nothing Eklemek için Ayarlar düzenleyicisinde hiçbir öğe olmadığında.

çare

Formdaki ayar koleksiyonunu başlat Load Gerekirse / gerektiğinde olay işleyici:

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

Genellikle, Settings koleksiyon sadece uygulama ilk kez çalıştırıldığında başlatılmalıdır. Alternatif bir çözüm, koleksiyonunuza ilk bir değer eklemektir. Proje -> Ayarlar | FooBarsprojeyi kaydedin, sonra sahte değeri kaldırın.


Anahtar noktaları

Muhtemelen unuttun. New Şebeke.

veya

Başladığın bir şey, kodlanmış bir nesneyi koduna döndürmek için kusursuz bir şekilde çalıştı.

Derleyici uyarılarını (hiç) görmezden gelme ve kullanma Option Strict On (her zaman).


MSDN NullReference İstisnası


273





Başka bir senaryo, boş bir nesneyi değer türü. Örneğin, aşağıdaki kod:

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

Bir atar NullReferenceException dökümde. Yukarıdaki örnekte oldukça belirgindir, ancak bu, null nesnenin sahip olmadığınız bir koddan döndüğü ve dökümün örneğin bazı otomatik sistem tarafından oluşturulduğu daha "geç bağlama" karmaşık senaryolarında gerçekleşebilir.

Bunun bir örneği, Takvim denetimi ile bu basit ASP.NET bağlama parçacığıdır:

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

İşte, SelectedDate aslında bir özelliktir DateTime türünün Calendar Web Kontrol tipi ve ciltleme, mükemmel bir şeyi boşa döndürür. Örtülü ASP.NET Üreticisi, yukarıdaki döküm koduna eşdeğer bir kod parçası oluşturacaktır. Ve bu bir yükselecek NullReferenceException Bu oldukça zor, çünkü ASP.NET üretilen kod içinde iyi derler ...


217



Büyük yakalamak. Kaçınılması gereken tek liner yolu: DateTime x = (DateTime) o as DateTime? ?? defaultValue; - Serge Shultz


Bu, söz konusu değişkenin hiçbir şeye işaret ettiği anlamına gelir. Bunu şöyle yapabilirim:

SqlConnection connection = null;
connection.Open();

Bu, hatayı atar, çünkü değişkeni ilan ettiğimdeconnection", hiçbir şeye işaret etmiyor. Üye aramaya çalıştığımda"Open", çözülmesi gereken bir referans yok ve bu hataya neden olacak.

Bu hatayı önlemek için:

  1. Nesnelerinizi her zaman bir şey yapmaya başlamadan önce başlatınız.
  2. Nesnenin boş olup olmadığından emin değilseniz, object == null.

JetBrains 'Resharper aracı, null bir kontrol hatası koymanıza olanak tanıyan, kodunuzdaki her yeri tanımlayacaktır. Bu hata, hataların bir numaralı kaynağı olan IMHO'dur.


146



JetBrains 'Resharper aracı, kodunuzdaki boş bir referans hatası olasılığına sahip her yeri tanımlar. Bu yanlış. Bu tespit olmadan bir çözümüm var, ancak kod bazen istisna ile sonuçlanıyor. Zaman zaman tespit edilemediğinden şüpheleniyorum - en azından onlar tarafından - multithreading söz konusu olduğunda, ama daha fazla yorum yapamam çünkü henüz hatanın yerini belirlemedim. - j riv
Ancak, NullReferenceException, HttpContext.Current.Responce.Clear () öğesinde geldiğinde nasıl çözülür. Yukarıdaki çözümlerden herhangi biriyle çözülmez. Çünkü HttpContext nesnesinin nesnesini oluştururken bir hata geliyor "Aşırı yükleme çözünürlüğü başarısız oldu çünkü erişilebilir 'Yeni' bu Bağımsız değişken sayısını kabul etmiyor. - Sunny Sandeep


Bu, kodunuzun null olarak ayarlanmış bir nesne referans değişkeni kullandığı anlamına gelir (yani, gerçek bir nesne örneğine başvurmadı).

Hatayı önlemek için, null olabilecek nesneler kullanılmadan önce null olarak test edilmelidir.

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





Senaryodan bağımsız olarak, nedeninin her zaman .NET'te aynı olduğunu unutmayın:

Değeri olan bir referans değişkeni kullanmaya çalışıyorsunuz Nothing/null. Değer ne zaman Nothing/null referans değişkeni için, bu aslında, yığın üzerinde bulunan herhangi bir nesnenin bir örneğine bir başvuru tutmadığı anlamına gelir.

Ya hiçbir zaman değişkene bir şey vermediniz, hiçbir zaman değişkene atanan değerin bir örneğini yaratmadınız ya da Nothing/null el ile veya değişkeni ayarlayan bir işlev çağırdınız Nothing/null senin için.


90





Bu istisnanın bir örneği atılıyor: Bir şeyleri kontrol etmeye çalıştığınızda, bu boş.

Örneğin:

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 çalışma zamanı, yukarıdaki örnekte bulunulmamış bir şey üzerinde bir eylem gerçekleştirmeye çalıştığınızda NullReferenceException atar.

Bir yöntemin kendisine geçirilmekte olanın null olmadığını umarsa, tipik olarak bir savunma önlemi olarak atılan bir ArgumentNullException ile karşılaştırıldığında.

Daha fazla bilgi C # NullReferenceException ve Boş Parametre.


76





Bir referans türünü başlatmamışsanız ve özelliklerinden birini ayarlamak veya okumak istiyorsanız, NullReferenceException.

Örnek:

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

Değişkenin boş olmadığını kontrol ederek bunu önleyebilirsiniz:

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

NullReferenceException neden atıldığını tam olarak anlamak için, arasındaki farkı bilmek önemlidir değer türleri ve referans tipleri.

Yani, eğer sen ilgileniyorsan değer türleri, NullReferenceExceptions şunları yapabilir değil meydana gelir. Bununla uğraşırken uyanık olmanız gerekse de referans tipleri!

Adından da anlaşılacağı gibi, yalnızca referans türleri, referansları tutabilir ya da tam anlamıyla hiçbir şeye işaret edemez (ya da 'boş'). Oysa değer türleri her zaman bir değer içerir.

Referans türleri (bunlar kontrol edilmelidir):

  • dinamik
  • nesne
  • sicim

Değer türleri (bunlardan kolayca görmezden gelebilirsiniz):

  • Sayısal türler
  • İntegral tipleri
  • Kayan nokta türleri
  • ondalık
  • bool
  • Kullanıcı tanımlı yapılar

72



-1: soru "NullReferenceException nedir" olduğundan, değer türleri uygun değildir. - John Saunders
@John Saunders: Katılmıyorum. Bir yazılım geliştiricisi olarak, değer ve referans türleri arasında ayrım yapabilmek gerçekten önemlidir. Başka bir deyişle, tamsayılar boş olup olmadığını denetler. - Fabian Bigler
Doğru, bu soru bağlamında değil. - John Saunders
İpucu için teşekkürler. Biraz geliştirdim ve üstüne bir örnek ekledim. Hala Referans ve Değer Türleri'nin yararlı olduğunu düşünüyorum. - Fabian Bigler
Bence diğer cevaplarda olmayan bir şey eklemediniz, çünkü soru bir referans türü öneriyor. - John Saunders