Neden “nesne başvurusu bir nesnenin örneğine ayarlanmadı” bize hangi nesneyi anlatmıyor?


39

Bir sistemi başlatıyoruz ve bazen NullReferenceExceptionmesajla ünlü istisnayı alıyoruz Object reference not set to an instance of an object.

Bununla birlikte, neredeyse 20 nesneye sahip olduğumuz bir yöntemde, bir nesnenin boş olduğunu söyleyen bir kütüğe sahip olmak gerçekten de hiçbir işe yaramaz. Bir seminerin güvenlik ajanı olduğunuzda, 100 katılımcının arasından birinin terörist olduğunu söylemek gibi. Bu gerçekten senin için hiçbir faydası yok. Hangi adamı tehdit eden adam olduğunu tespit etmek istiyorsanız daha fazla bilgi edinmelisiniz.

Aynı şekilde, hatayı kaldırmak istiyorsak hangi nesnenin boş olduğunu bilmemiz gerekir.

Şimdi, bir şey birkaç aydır kafamı kafamı karıştırdı ve bu:

.NET neden bize adını veya en azından null olan nesne başvurusunun türünü vermiyor? . Yansımayı veya başka bir kaynaktan türünü anlayamıyor mu?

Ayrıca, hangi nesnenin boş olduğunu anlamak için en iyi uygulamalar nelerdir? Bu bağlamlardaki nesnelerin çekilebilirliğini her zaman manuel olarak test etmeli ve sonucu kaydetmeli miyiz? Daha iyi bir yolu var mı?

Güncelleme: İstisna The system cannot find the file specifiedaynı yapıya sahip. İşleme ekleyip hata ayıklamadıkça hangi dosyayı bulamazsınız. Bu tür istisnalar daha akıllı hale gelebilir. .NET c:\temp.txt doesn't exist.bu genel mesaj yerine bize söylerse daha iyi olmaz mıydı ? Bir geliştirici olarak, oy kullanıyorum.


14
İstisna, satır numarasına sahip bir yığın izi içermelidir. Araştırmaya oradan, o hattan erişilen her cisme bakarak başlayacağım.
PersonalNexus,

2
Ayrıca, Visual Studio'daki istisna yardımcı iletişim kutusunun neden newbir sınıfın örnekleri oluşturmak için kullanılacak "yararlı" ipucu içerdiğini her zaman merak etmişimdir . Böyle bir ipucu ne zaman gerçekten işe yarıyor?
PersonalNexus,

1
On nesne çağrısından oluşan bir zinciriniz varsa, tasarımınızdaki bağlantı ile ilgili bir probleminiz vardır.
Pete Kirkham


9
Bu soruya verilen her cevabın, "Bir hata ayıklayıcı kullanın, hatalarınızı kaydedin, null'u kontrol edin, yine de sizin suçunuzdur" satırları boyunca nasıl bir soru sorduğuna bayılırım. Yalnızca yığın akışı üzerinde biri size gerçekten bir cevap verir (bence VM'nin takip edemeyeceği kadar çok yükü var). Fakat gerçekten, bu soruyu doğru cevaplayabilecek tek kişi, çerçevede çalışan microsoft’tan birileri.
Rocklan

Yanıtlar:


28

Temel NullReferenceExceptionolarak size söyler: yanlış yapıyorsunuz. Ne fazla ne eksik. Aksine, tam teşekküllü bir hata ayıklama aracı değildir. Bu durumda, her ikisini de yanlış yaptığınızı söyleyebilirim çünkü

  • NullReferenceException var
  • neden / nerede olduğunu bildiğiniz bir şekilde engellemediniz
  • ve ayrıca belki: 20 nesne gerektiren bir yöntem biraz uzakta görünüyor

İşler ters gitmeden önce her şeyi kontrol etmenin ve geliştiriciye iyi bilgi vermenin büyük bir hayranıyım. Kısacası: çekleri kullanarak çek yazmayı ArgumentNullExceptionve hoşunuza gitti ve adı kendiniz yazın. İşte bir örnek:

void Method(string a, SomeObject b)
{
    if (a == null) throw ArgumentNullException("a");
    if (b == null) throw ArgumentNullException("b");

    // See how nice this is, and what peace of mind this provides? As long as
    // nothing modifies a or b you can use them here and be 100% sure they're not
    // null. Should they be when entering the method, at least you know which one
    // is null.
    var c = FetchSomeObject();
    if(c == null)
    {
        throw InvalidOperationException("Fetching B failed!!");
    }

    // etc.
}

Ayrıca Kod Sözleşmelerine de bakabilirsiniz , tuhaflıkları vardır ancak oldukça iyi çalışır ve bazı yazımlardan tasarruf etmenizi sağlar.


17
@SaeedNeamati, büyük bir kod temeli bulunduğundan, düzgün bir hata denetimi yapmamanız gerektiği anlamına gelmiyor. Proje büyüdükçe, rol veya hata kontrolü ve raporlamanın önemi artar.
stijn

6
Asıl soruya cevap vermese bile, iyi tavsiye için +1 (ki muhtemelen sadece Anders Hejlsberg cevaplayabilir).
Ross Patterson

12
Mükemmel tavsiye için +1. @SaeedNeamati bu tavsiyeyi dinlemelidir. Sorununuz, dikkatsizlik ve koddaki profesyonellik eksikliğinden kaynaklanıyor. İyi kod yazmak için zamanınız yoksa, çok daha büyük sorunlarınız var ...
MattDavey

3
İyi kod yazmak için zamanınız yoksa , kesinlikle kötü kod yazmak için zamanınız yok . Kötü kod yazmak, iyi kod yazmaktan daha uzun sürer. Tabii böcekleri gerçekten umursamıyorsan. Eğer eğer gerçekten hatalar umurumda değil, neden hiç program yazabilir?
MarkJ

5
@ SaeedNeamati I only say that checking every object to get sure that it's not null, is not a good methodCidden. En iyi yöntem bu. Ve sadece boş değil, her argümanı makul değerler için kontrol edin. Hataları ne kadar erken yakalarsanız, nedeni bulmak o kadar kolay olur. Neden olan aramayı bulmak için yığın izlemesinde birkaç düzeyi izlemek zorunda kalmazsınız.
jgauffin

19

Gerçekten ne aramaya çalıştığını tam olarak göstermeli. "Bir sorun var. Bunu düzeltmelisin. Ne olduğunu biliyorum. Sana söylemeyeceğim. Bunu çözeceksin." Demesi gibi. Bu Yığın Taşması ile ilgili cevapların yarısı gibi, ironik bir şekilde.

Öyleyse ne kadar faydalı olurdu, örneğin, eğer bunu aldıysanız ...

Object reference (HttpContext.Current) not set to instance of an object

...? Koda girmeniz, adım adım ilerlemeniz ve aramaya çalıştığınız şeyin nulliyi olduğunu hesaplayın, ancak neden bize biraz yardım eli vermiyorsunuz?

Cevabı bulmak için kodda ilerlemenin genellikle yararlı olacağını kabul ediyorum (çünkü muhtemelen daha fazlasını öğreneceksiniz), ancak NullReferenceExceptionmetin yukarıdaki örnekte olduğu gibi olsaydı sık sık zamandan ve sıkıntıdan kurtuluruz .

Sadece söylüyorum.


Çalışma zamanının gerçekte null olduğunu bilmesi nasıl mümkün olabilir?
Will

3
Çalışma zamanı, sağladığından daha fazla bilgiye sahip. Hangi faydalı bilgiye sahip olursa olsun sağlamalıdır. Tüm söylediğim bu. Sorunuza cevap olarak, neden bilmiyor? Bunun cevabını biliyorsanız, sizinkinden daha iyi bir yorumda bulunabilirsiniz.
LiverpoolsNumber9

Anlaştık ve aynı KeyNotFoundExceptionve diğer birçok sıkıntı için de aynısını söyleyebilirim ...
sinelaw 19.03.2013

Aslında, sıfırın kaldırılması durumunda bu , CLR kurallarının kaldırılmasında bir sınırlama gibi gözükmektedir (Shahrooz Jefri'nin OP'nin sorusu üzerine yaptığı yorum sayesinde)
sinelaw


4

Günlüğünüz bir yığın izlemesi içermelidir - bu, genellikle yöntemde hangi satırda sorun olduğunu gösteren bir ipucu verir. Yayınınızın PDB sembollerini içermesini sağlamanız gerekebilir, böylece hatanın hangi satırda olduğu hakkında bir fikriniz olur.

Verilmiş, bu durumda size yardımcı olmaz:

Foo.Bar.Baz.DoSomething()

Söyle sormayın böyle kod önlemek için prensip kutu yardım.

Bilginin neden dahil edilmediğine gelince, emin değilim - En azından bir hata ayıklama yapısında, gerçekten isterlerse çözebileceklerinden şüpheleniyorum. Bir çökme dökümü almak ve WinDBG'de açmak yardımcı olabilir.


2

İstisnalar, ölümcül olmayan istisnai durumları çağrı zincirine kadar bildiren bir araç olarak yaratılmıştır . Yani, bir hata ayıklama aracı olarak tasarlanmamıştır.

Bir boş gösterici istisnası, bir hata ayıklama aracı olsaydı, tam yerinde bir hata ayıklayıcının bağlanmasına izin vererek doğrudan suçlama hattına işaret ederek programın çalışmasını iptal ederdi. Bu programcıya mevcut tüm içerik bilgisini verir. (Boş bir işaretçi erişimi nedeniyle yapılan bir Segfault'un C de biraz kabaca olsa da, ne yaptığıdır.)

Bununla birlikte, boş gösterici istisnası, normal program akışında atılabilen ve yakalanabilen geçerli bir çalışma zamanı koşulu olarak tasarlanmıştır. Sonuç olarak, performans hususları dikkate alınmalıdır. İstisna mesajının herhangi bir şekilde özelleştirilmesi, çalışma zamanında yaratılma, birleştirme ve imha etme gibi string nesneler gerektirir. Bu nedenle, statik bir mesaj tartışmasız daha hızlıdır.

Çalışma zamanının suçlayıcı referansın adını verecek şekilde programlanamayacağını söylemiyorum. Bu yapılabilir. Bu sadece istisnaları onlardan daha yavaş yapacaktır. Biri yeterince önemserse, böyle bir özellik bile üretim kodunu yavaşlatmayacak, ancak daha kolay hata ayıklamaya izin verecek şekilde değiştirilebilir hale getirilebilir; ama nedense kimse yeterince umursamıyor gibi görünüyor.


1

Cromulent bence kafanın üstündeki çiviyi vurdu, ancak bariz bir nokta var ki, eğer bir tane elde NullReferenceExceptionederseniz başlatılmamış değişken (ler) iniz var. Bir yönteme yaklaşık 20 nesne iletildiğinin argümanının hafifletici olduğu söylenemez: kodun bir parçasının yaratıcısı olarak, bir kod tabanının geri kalanına uyumunu da içeren, yaptıklarından sorumlu olmak zorundasınız. değişkenlerin doğru ve doğru kullanımı vs.

zahmetli, sıkıcı ve bazen sıkıcı ama sonunda ödüller buna değer: birçoğu gigabayt ağırlığındaki kütük dosyalarında dolaşmak zorunda kaldığım zamanlardı ve neredeyse her zaman yardımcı oluyorlar. Ancak bu aşamaya gelmeden önce, hata ayıklayıcı size yardımcı olabilir ve bu aşamadan önce iyi planlama çok fazla acı kazandıracak (ve size kod çözümü için tamamen tasarlanmış bir yaklaşım anlamına gelmez: basit çizimler ve bazı notlar hiçbir şeyden daha iyi olmak.

Kodla ilgili olarak Object reference not set to an instance of an objectbizim isteyebileceğimiz değerlerde tahmin edemezsiniz: programlayıcı olarak bizim işimiz ve bu basitçe içinde başlatılmamış bir değişkeni geçtiğin anlamına gelir.


Assembly dilinde yazmak için bu gibi gerekçeleri sunan kişilerin farkında mısın? Ve otomatik çöp toplama kullanmıyor musunuz? Ve aritmetik yapabilmek - onaltılı? "zahmetli, sıkıcı ve bazen sıkıcı", otomatikleştirilmesi gereken işleri nasıl tanımladığımızdır.
Spike0xff 28:15

0

Hata ayıklayıcıyı kullanmayı öğrenin. Bu tam olarak onun için tasarlandığı türden bir şey. Söz konusu yönteme bir mola noktası koyun ve uzağa gidin.

Kodunuzda ilerleyin ve tüm değişkenlerinizin değerlerinin tam olarak ne olduğunu görün.

Düzenleme: Açıkçası ben henüz hata ayıklayıcı kullanarak başka kimsenin bahsetmediği için şok oldum.


2
Yani, bir hata ayıklayıcı kullanırken tüm istisnaların kolayca yeniden üretilebileceğini söylüyorsunuz?
jgauffin

@jgauffin Söz konusu kodu tam olarak sınamayan sentetik birim testleri yerine gerçek dünya kodunda bir istisnanın neden ortaya çıktığını görmek için bir hata ayıklayıcı kullanabileceğinizi veya birim testlerinin kendilerinin neden olduğu hatalara sahip olabileceğini söylüyorum gerçek koddaki hataları özlüyorlar. Bir hata ayıklayıcı düşünebildiğim herhangi bir araçtan (belki de Valgrind veya DTrace gibi şeyler hariç) çok fazla hata yapar.
Cromulent

1
Yani her zaman başarısız olan bilgisayara erişebildiğimizi ve hata ayıklamanın birim testlerinden daha iyi olduğunu mu söylüyorsunuz?
Şubat'ta jgauffin

@jgauffin Diyorum ki, eğer bir seçeneğiniz varsa, diğer araçları tercih etmek için hata ayıklayıcınızla gidin. Tabii ki bu seçeneğiniz yoksa, o zaman biraz başlangıçsız. Açıkçası bu, bu sorunun cevabı değil, bu yüzden yaptığım cevabı verdim. Eğer soru, uzaktan hata ayıklama (ya da yerel hata ayıklama) yapmanın bir yolu olmayan bir istemci bilgisayarda bu sorunu nasıl düzeltirmiş olsaydı cevabım farklı olurdu. Elimdeki soru ile alakası olmayan yollarla cevabımı çarpıtmaya çalışıyor gibisin.
Cromulent

0

@ Stijn'in cevabını bulmak ve kodunuza boş kontroller koymak istiyorsanız, bu kod pasajının yardımcı olması gerekir. İşte kod parçacıkları hakkında bazı bilgiler . Bu ayarları yaptıktan sonra, sadece argnulliki kez sekmeye basın, ardından boşluğu doldurun.

<CodeSnippet Format="1.0.0">
  <Header>
    <Title>EnsureArgNotNull</Title>
    <Shortcut>argnull</Shortcut>
  </Header>
  <Snippet>
    <Declarations>
      <Literal>
        <ID>argument</ID>
        <ToolTip>The name of the argument that shouldn't be null</ToolTip>
        <Default>arg</Default>
      </Literal>
    </Declarations>
    <Code Language="CSharp">
      <![CDATA[if ($argument$ == null) throw new ArgumentNullException("$argument$");$end$]]>
    </Code>
  </Snippet>
</CodeSnippet>

not: c # 6 şimdi, nameofpasajınızın throw new ArgumentNullException(nameof($argument$))sihirli sabitleri içermemeyi, derleyici tarafından kontrol edilmeyi ve yeniden düzenleme araçlarıyla daha iyi çalışmayı sağlama avantajlarına sahip olabileceğini söyledi
stijn
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.