C# "System.NullReferenceException: Object reference not set to an instance of an object." hatası, null değer taşıyan bir nesne başvurusu üzerinden bir özelliğe veya metoda erişildiğinde oluşur. Çözüm, hatalı satıra rastgele bir null kontrolü eklemek değil, stack trace'teki uygulama satırını bulmak, hangi başvurunun null kaldığını belirlemek, bunun nedenini düzeltmek ve aynı akışı yeniden test etmektir.
Hatanın görüldüğü satır, null değerinin ortaya çıktığı an olmayabilir. Bir değişken daha önce tanımlanmış olsa bile bir nesne örneğine işaret etmiyorsa bu hata oluşabilir. Bu nedenle önce null ile oluşturulmuş bir nesne arasındaki farkı anlamak gerekir.
System.NullReferenceException ne anlama gelir?

null, boş bir nesne anlamına gelmez. Bir başvurunun herhangi bir nesne örneğine işaret etmediğini ifade eder. Örneğin Profil profil = null; kodunda profil adlı başvuru değişkeni vardır, fakat ortada kullanılabilecek bir Profil nesnesi yoktur. Bu durumda profil.Ad veya profil.Goster() gibi bir erişim yapılırsa System.NullReferenceException oluşur.
class Profil
{
public string Ad { get; set; }
}
class Program
{
static void Main()
{
Profil profil = null;
// System.Console.WriteLine(profil.Ad);
profil = new Profil();
profil.Ad = "Ada";
System.Console.WriteLine(profil.Ad);
}
}
Yorum satırındaki erişim çalıştırılırsa hata profil.Ad ifadesinde görülür. profil = new Profil(); ile gerçek bir nesne oluşturulduktan sonra kod çalışır ve beklenen çıktı Ada olur. Ayrıca nesnenin var olması, içindeki her değerin dolu olduğu anlamına gelmez. Örneğin Ad özelliği null kalırsa profil.Ad.Length gibi devam eden bir erişim yine aynı hataya yol açabilir.
Hata satırında yalnızca profil başvurusunu görmen, null değerinin mutlaka o satırda üretildiği anlamına gelmez. Başvuru daha önce bir metottan null dönmüş, bir atama adımı atlanmış veya başka bir işlem sonrasında null hâle gelmiş olabilir. Kodu değiştirmeden önce nesne, başvuru ve null kavramlarındaki bilgi düzeyini değerlendirmek için C# bilgi testi kullanılabilir. Böylece temel kavramlarla belirli bir kod akışındaki atama sorununu birbirinden ayırarak incelemeye başlayabilirsin.
Stack trace ile sorunlu satır ve null değer nasıl bulunur?
Stack trace, istisnanın çağrı zincirini gösterir. İncelemeye önce kendi uygulama koduna ait dosya adı, metot adı ve satır numarasından başla. Kütüphane veya çalışma zamanı satırlarını hemen düzeltmeye çalışmak yerine, stack trace içinde sana ait kodun bulunduğu ilk anlamlı satırı belirlemek daha sağlıklı bir başlangıçtır.
Sorunlu ifadede birden fazla nesne veya özellik varsa zinciri tek parça olarak değerlendirme. ogrenci.Profil.Ad ifadesinde önce ogrenci başvurusunun null olup olmadığını, ardından ogrenci.Profil sonucunun kullanılabilir bir nesne gösterip göstermediğini kontrol et. Ad değerinin kendisi null ise hata, bu değerin başka bir özelliğine veya metoduna erişildiğinde ortaya çıkabilir. Null kalan ara değerin nerede oluşturulması gerektiğini, hangi atamayla değiştiğini ve ilk kez nerede kullanıldığını geriye doğru izle.
- Sorunlu satırı bul.
- Null kalan değeri izle.
- Null kaynağını dört kategoriden biri olarak sınıflandır.
- Kök nedeni düzelterek yeniden test et.
Bu yaklaşım, tek satırdaki hatayı bütün programın sorunu gibi ele almak yerine problemi parçalara ayırmayı ve her adımda değişkenlerin durumunu takip etmeyi sağlar. Düzeltmeye başlamadan önce Algoritmik Düşünme Testi, bu iki beceriyi değerlendirmek için kullanılabilir.
Null kalan nesneler hangi dört kaynaktan doğar?

null kalan referansın kaynağı çoğu zaman hatanın oluştuğu satırdan önce verilen bir karardır. En sık görülen dört kaynak aşağıdaki gibidir.
Nesneyi oluşturmamak veya constructor içinde başlatmamak
Neden: Referans için new çağrısı yapılmamış olabilir. Belirti: Referansın ilk üyesine erişildiğinde istisna oluşur.
class Report
{
public string Title { get; set; }
}
Report report = null;
Console.WriteLine(report.Title);
Buradaki önceki karar, report değişkenini null bırakıp new Report() oluşturmamaktır. Dış nesne oluşturulsa bile constructor gerekli alanı atamazsa benzer hata ortaya çıkabilir.
class UserProfile
{
public string DisplayName;
public UserProfile()
{
}
}
var profile = new UserProfile();
Console.WriteLine(profile.DisplayName.Length);
Bu örnekte profile vardır, ancak constructor DisplayName alanını doldurmadığı için alan null kalır. Düzeltme: Zorunlu alanları constructor içinde başlatmak veya geçerli bir değer almadan nesneyi kullanmamaktır.
Atamayı yalnızca belirli bir koşula bağlamak
Neden: Atama yalnızca bir koşul doğru olduğunda yapılır. Belirti: Koşulun sağlanmadığı akışta referans boş kalır.
string message = null;
bool includeDetails = false;
if (includeDetails)
{
message = "Ayrıntılar";
}
Console.WriteLine(message.Length);
Null değerin kaynağı, includeDetails değerinin false olması ve atamanın yapılmamasıdır. Düzeltme: Her akışta geçerli bir değer üretmek, koşul sağlanmadığında işlemi sonlandırmak veya yokluğun geçerli olup olmadığını açıkça kontrol etmektir.
Koleksiyonun içinde null eleman bulundurmak
Neden: Koleksiyonun kendisi oluşturulmuş olsa da içine null bir eleman eklenmiş olabilir. Belirti: Döngü, belirli bir elemana geldiğinde o elemanın üyesine erişemez.
var names = new System.Collections.Generic.List<string>
{
"Ada",
null,
"Linus"
};
foreach (var name in names)
{
Console.WriteLine(name.Length);
}
Buradaki önceki karar, koleksiyona null değer eklenmesine izin vermektir. Düzeltme: Elemanı eklerken geçersiz değeri reddetmek, koleksiyonu kullanmadan önce temizlemek veya null değer geçerliyse her eleman için uygun kontrolü yapmaktır.
Nesnenin veya alt nesnenin kesinlikle var olduğunu varsaymak
Neden: Dış nesne oluşturulduğunda alt nesnenin de otomatik olarak oluşacağı varsayılır. Belirti: Dış nesneye erişilebilirken iç içe üye erişiminde istisna oluşur.
class Order
{
public Customer Customer { get; set; }
}
class Customer
{
public string Name { get; set; }
}
var order = new Order();
Console.WriteLine(order.Customer.Name);
Önceki karar, new Order() çağrısının Customer nesnesini de oluşturduğunu varsaymaktır. Oysa alt nesne ayrıca atanmadığı için order.Customer null kalır. Düzeltme: Alt nesneyi constructor içinde oluşturmak, dışarıdan zorunlu olarak almak veya veri kaynağından gelen null sonucu açıkça ele almaktır.
Kök neden nasıl düzeltilir ve çözüm nasıl test edilir?
Kalıcı çözüm, her erişim satırına rastgele bir null kontrolü eklemek değil, zorunlu nesnenin ne zaman ve kim tarafından oluşturulacağını netleştirmektir.
Gerekli alt nesneyi constructor ile güvenceye almak
using System;
public sealed class NameCard
{
public string Name { get; }
public NameCard(string name)
{
if (name == null)
{
throw new ArgumentNullException(nameof(name));
}
Name = name;
}
}
public sealed class Student
{
private readonly NameCard nameCard;
public Student(NameCard nameCard)
{
if (nameCard == null)
{
throw new ArgumentNullException(nameof(nameCard));
}
this.nameCard = nameCard;
}
public void PrintName()
{
Console.WriteLine(nameCard.Name);
}
}
public static class Program
{
public static void Main()
{
var nameCard = new NameCard("Ada");
var student = new Student(nameCard);
student.PrintName();
}
}
Beklenen çıktı: Ada
Bu örnekte Student sınıfı ihtiyaç duyduğu NameCard nesnesini constructor üzerinden alır. Geçersiz null girdi, daha sonra üye erişiminde belirsiz bir hata oluşturmak yerine constructor sınırında reddedilir.
if ve ?. seçimini kök nedene göre yapmak
if (nesne != null) kontrolü, nesnenin yokluğunun geçerli olduğu durumlarda uygundur. Örneğin isteğe bağlı bir kayıt bulunamadığında işlemi atlamak mantıklı olabilir. nesne?.Uye veya nesne?.Metot() kullanımı da benzer biçimde yokluğu güvenli şekilde taşır. Ancak nesne zorunluysa işlemi sessizce atlamak kök nedeni gizleyebilir. Bu durumda constructor, veri doğrulama veya doğru başlatma düzeni düzeltilmelidir.
Çözümü yeniden test etmek
- Geçerli nesne: Gerekli alt nesneler oluşturulmuşken beklenen değerin, örnekte olduğu gibi
Adadeğerinin üretildiğini kontrol et. - Geçersiz constructor girdisi:
new Student(null)veyanew NameCard(null)gibi girişlerde hatanın sınırda ve anlaşılır bir istisna olarak yakalandığını doğrula. - Koşullu atama: Koşul hem doğru hem yanlışken kodu çalıştır. Her iki akışta da geçerli bir değer üretilmeli veya işlem açıkça sonlandırılmalıdır.
- Koleksiyon elemanı: Hem normal hem de
nulleleman içeren koleksiyonla test yap. Uygulamanın bu elemanı reddetme, atlama veya kontrollü biçimde işleme kararının beklenen sonucu verdiğini kontrol et.
Sık Sorulan Sorular
Null-conditional operatörü ?. NullReferenceException hatasını tamamen çözer mi?
Hayır. ?. belirli bir erişimde nesne null ise istisnayı önleyebilir, ancak eksik nesnenin neden oluştuğunu düzeltmez. Nesne zorunluysa bu kullanım hatayı gizleyebilir veya null sonucu başka bir satıra taşıyabilir.
new ile oluşturduğum bir nesnede neden yine NullReferenceException oluşabilir?
new yalnızca dış nesneyi oluşturur. Alanlar, özellikler, alt nesneler veya koleksiyon elemanları ayrıca başlatılmadıysa null kalabilir. Constructor içinde eksik atama yapılması da aynı sonuca yol açar.
Stack trace birden fazla çağrı gösteriyorsa incelemeye hangi satırdan başlanmalıdır?
Önce stack trace içindeki, uygulamana ait ve istisnanın oluştuğu satırı incele. Ardından bu metoda gelen çağrı zincirinde geriye doğru ilerleyerek null değerin hangi önceki karardan kaynaklandığını bul.
NullReferenceException için kalıcı yaklaşım, yalnızca hatayı bastırmak değil, null değerin kaynağını düzeltmek ve farklı veri akışlarıyla yeniden test etmektir.