Nesne başvurusu bir nesnenin örneğine ayarlanmadı. .NET neden hangi nesnenin "boş" olduğunu göstermiyor?


103

Bu .NET işlenmemiş istisna mesajıyla ilgili olarak:

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

Neden .NET hangi nesnenin olduğunu göstermiyor null?

nullHatayı kontrol edip çözebileceğimi biliyorum . Ancak, neden .NET hangi nesnenin boş referansa sahip olduğunu ve hangi ifadenin NullReferenceException?

c#  .net 

2
Bu olduğunda, meydana geldiği satırı yeniden yazın, böylece önce her olası sonucu sıfır olarak kontrol eder - sonra tam olarak ne olduğunu bilirsiniz. Ya bu, ya da Visual Studio'nun inanılmaz hata ayıklayıcısını
eklediniz

5
Aslında değil, sadece .NET çerçevesinin programcının hangi nesnenin boş olduğunu göstermesine neden yardımcı olmadığını sorar . Sanırım bu performans cezası (düşünmeye ihtiyacınız olacak). ama ben de emin değilim.
bas

1
@bas: Bu doğru olsa da, soru biraz yanıltıcı çünkü bir "nesne" değil, "ifadenin bir parçası" hakkında soru sorulmalı. Bu aynı zamanda neden yalnızca yansımanın yardımcı olmayacağını açıklar, ancak bazı kapsamlı hata ayıklama bilgileri gerekecektir.
OR Mapper

4
Yine de cevabı merak ediyorum. .Net istisnalarına benzer şekilde , bir sözlükte hangi anahtarın olmadığını göstermeye yardımcı olmaz. Ayrıca, sorudaki özverileri de anlamıyorum.
bas

12
Terminoloji lütfen: Bir nesne asla boş değildir. Yine de bir nesne referansı olabilir. Ancak bir nesne referansı yalnızca bellekteki bir konumdur - yine de eklenmiş bir hata ayıklayıcınız yoksa size nasıl yardımcı olur?
Oskar Berggren

Yanıtlar:


169

(Visual Studio 2017'deki yeni istisna yardımcısı hakkında bilgi için bu cevabın sonuna bakın)


Bu kodu düşünün:

String s = null;
Console.WriteLine(s.Length);

Bu NullReferenceExceptionikinci satıra bir atar ve .NET'in neden sistisna atıldığında boş olduğunu söylemediğini bilmek istersiniz .

Bu bilgiyi neden almadığınızı anlamak için, çalıştıranın C # kaynağı değil, IL olduğunu hatırlamanız gerekir:

IL_0001: ldnull      
IL_0002: stloc.0 // s
IL_0003: ldloc.0 // s
IL_0004: callvirt System.String.get_Length
IL_0009: System.Console.WriteLine'ı çağırın

Bu ise callvirtatar işlem kodu NullReferenceExceptionve yapar değerlendirme yığın ilk bağımsız boş bir referans (kullanılarak yüklenmiştir bir olduğunda ldloc.0).

Eğer .NET bunun sboş bir referans olduğunu söyleyebiliyorsa , bir şekilde değerlendirme yığınındaki ilk argümanın form kaynaklı olduğunu izlemelidir s. Bu durumda, sbunun boş olduğunu görmek bizim için kolaydır, ancak ya değer başka bir işlev çağrısından bir dönüş değeriyse ve herhangi bir değişkende depolanmamışsa? Her neyse, bu tür bilgiler, .NET sanal makinesi gibi bir sanal makinede takip etmek isteyeceğiniz şeyler değildir.


Bu sorunu önlemek için, tüm genel yöntem çağrılarında argüman null denetimi yapmanızı öneririm (tabii ki boş referansa izin vermezseniz):

public void Foo(String s) {
  if (s == null)
    throw new ArgumentNullException("s");
  Console.WriteLine(s.Length);
}

Yönteme null geçirilirse, sorunun ne olduğunu tam olarak açıklayan bir istisna elde edersiniz (bu s, boştur).


Dört yıl sonra Visual Studio 2017, artık bir NullReferenceExceptionatıldığında neyin null olduğunu söylemeye çalışan yeni bir istisna yardımcısına sahip . Hatta boş olan bir yöntemin dönüş değeri olduğunda size gerekli bilgileri verebilir:

Visual Studio 2017 istisna yardımcısı

Bunun yalnızca bir DEBUG yapısında çalıştığını unutmayın.


5
Satır numaraları ve kaynak dosya adları IL kodunun kendisinde depolanmaz mı, yoksa öyle mi? Yine de hata ayıklama için kullanılabilir hale getirilebilirler.
OR Mapper

4
@MartinLiversage: Kesinlikle. Öyleyse soru şu şekildedir: Sembol dosyalarında, koddaki hangi ifadenin değerlendirildiğini de belirten yeterli bilgi neden yok null?
OR Mapper

2
@MartinLiversage: Sembol dosyalarına, bir istisna durumunda istisna mesajıyla birlikte kaynak dosyası ve satır numarası hata ayıklayıcının çıktısında görüntülenebilecek şekilde erişilebilir. Öyleyse, soru şudur, tam olarak neyin döndürüldüğüne dair daha fazla bilgi eklememenin nedeni nedir null- OP'nin sürüm yapıları için de hata ayıklama yapılarının yeterli olabileceğini bilmek istediğini iddia etmediğini unutmayın.
OR Mapper

3
Hmm, ve aslında çalıştıranın IL bile olmadığını, çalışma zamanında ondan oluşturulan yerel kod olduğunu unutmamalıyız.
Oskar Berggren

2
@MartinLiversage: Bu sorudaki hiç kimse bunun sürüm yapıları için mükemmel şekilde desteklenmesini istediğimizi iddia etmiyor. Her neyse, bir nesne referansı kullanan (ortaya çıkabilecek) IL işlem kodunu nullkaynak dosya satırı ve bu nesne referansını döndüren sütun ile ilişkilendirmede problemi tam olarak görmüyorum .
OR Mapper

9

Aşağıdaki durumdaki hata mesajının nasıl görünmesini istersiniz?

AnyObject.GetANullObject().ToString();

private object GetANullObject()
{
  return null;
}

Burada rapor edilecek değişken adı yok!


2
OP'nin kaynak kodunda nesnede değil null döndüren ifadeyi aradığından şüpheleniyorum. Soruya bir yorum ekledim ve her şeyi açıklığa kavuşturacağını umuyorum. Şüphem doğruysa, OP Object reference obtained from AnyObject.GetANullObject() not set to an instance of an object.hata mesajı gibi bir şey bekler .
OR Mapper

1
@ORMapper Kabul ediyorum. Bir yorum eklemek için yeterli itibar puanım olsaydı, OP'ye bir yoruma "cevabımı" koyardım!
romar

1
"XYZ Sınıfının ToString () yöntemini çağırmaya çalışan bir boş referans" şu anda elde ettiğimizden daha yararlı olacaktır.
Michael Levy

En yararlı olan şey, her çağrı düzeyinde, hangi dosyadaki hangi satırın hatayla sonuçlandığını tam olarak gösteren bir yığın izleme olacaktır. Oh, bekle ... şimdi yaptığı şey bu!
Jim Balter

1

Bu cevap Microsoft'taki mühendislere kalmış. Ancak, açık bir şekilde bir hata ayıklayıcı kullanabilir ve bunlardan hangisinde sorun olduğunu bulmak için saat ekleyebilirsiniz.

Bununla birlikte, istisna, NullReferenceExceptionreferansın mevcut olmadığı anlamına gelir . Hiç yaratılmamış nesneyi alamazsınız.

but why .NET don't tell us which object is null? Çünkü hangi nesnenin boş olduğunu bilmiyor. Nesne basitçe mevcut değil!

C # .NET IL koduna derlendiğini söylediğimde de durum aynı. .NET IL kodu, adları veya ifadeleri bilmiyor. Sadece referansları ve yerlerini bilir. Burada da olmayanı alamazsınız. İfade veya değişken adı mevcut değil.

Felsefe: İlk etapta yumurtanız yoksa omlet yapamazsınız.


3
bu da bir cevap değil :)
bas

Eğer yoksa referansı nasıl alırsınız? @Bas
Aniket Inge

4
"Pekala, bu cevap Microsoft'taki mühendislerin elinde." Yani onları yerine bariz belirten bu ışık tutacak izin
bas

@bas en azından neyin mantıklı olduğuna karar verebiliriz. Mantıksal olarak nesne mevcut değildir. Bunu bir istisna ile nasıl yakalayacak ve sonra nesnenin adını nasıl yazdıracaksınız? Sadece mevcut değil.
Üst üste

öyleyse cevap şu ki, hangi nesnenin sıfır referansına sahip olduğunu belirtmek neredeyse imkansız? Bu da bir cevap. Bildiğimi belirtmiyorum, sadece soruyu beğendim :). Tüm çabalar için +1: p
bas

1

Emin değilim, ancak bunun nedeni .Net'in önceden tanımlanmış sınıf mı yoksa kullanıcı tanımlı mı olduğunu bilmemesi olabilir. Önceden tanımlanmışsa, boş olabilir (2 Bayt işgal eden dize gibi), ancak kullanıcı tanımlıysa, bunun bir örneğini oluşturmamız gerekir, böylece bu nesnenin bu kadar bellek kaplayacağını bilir. Bu nedenle çalışma zamanında hata verir.


-2

İyi soru. Mesaj kutusu işe yaramaz. Referans tanımından bir mil derine gömülmüş olsa bile, bazı sınıflar veya derlemeler veya dosyalar veya diğer bilgiler şu anda sağladıklarından daha iyi olacaktır (okuyun: hiç yoktan iyidir).

En iyi seçeneğiniz, onu hata ayıklayıcıda hata ayıklama bilgileriyle çalıştırmaktır ve IDE'niz sorunlu satırda kesilir (daha ziyade yararlı bilgilerin gerçekte mevcut olduğunu açıkça gösterir).

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.