Bazı kod var ve çalıştırdığında, atar NullReferenceException
, atar :
Nesne referansı bir nesnenin örneğine atanmadı.
Bu ne anlama geliyor ve bu hatayı düzeltmek için ne yapabilirim?
Bazı kod var ve çalıştırdığında, atar NullReferenceException
, atar :
Nesne referansı bir nesnenin örneğine atanmadı.
Bu ne anlama geliyor ve bu hatayı düzeltmek için ne yapabilirim?
Yanıtlar:
null
(Veya Nothing
VB.NET içinde) bir şey kullanmaya çalışıyorsunuz . Bu, ya ayarladığınız ya null
da hiçbir şeye ayarlayamayacağınız anlamına gelir .
Diğer her şey gibi, null
etrafından geçilir. Eğer durum bu ise null
de yöntemin "A", o yöntem "B" geçmiş olabilir null
için yöntemin "A".
null
farklı anlamları olabilir:
NullReferenceException
.null
kasıtlı olarak kullanıyor . C # değişkenleri için null olabilecek veri türleri kavramına sahip olduğunu unutmayın (veritabanı tabloları nullable alanları olabilir gibi) - null
bunlara depolanmış bir değer olmadığını belirtmek için atayabilirsiniz , örneğin int? a = null;
soru işareti null değerinin depolanmasına izin verildiğini gösterir değişken a
. Bunu ile if (a.HasValue) {...}
veya ile kontrol edebilirsiniz if (a==null) {...}
. a
Bu örnek gibi nullable değişkenleri, değere a.Value
açıkça veya normal şekilde erişilmesine izin verir a
. a.Value
bir atar InvalidOperationException
yerine ait NullReferenceException
ise a
, ISnull
- kontrolü önceden yapmalısınız, yani başka bir nullenebilen değişkeniniz int b;
varsa, o zaman if (a.HasValue) { b = a.Value; }
daha kısa ya da böyle atamalar yapmalısınız if (a != null) { b = a; }
.Bu makalenin geri kalan birçok programcılar genellikle yol açabilir yapmak daha detay ve gösteriler hatalardan gider NullReferenceException
.
runtime
Bir atma NullReferenceException
hep bir başvuru kullanmaya çalıştığınız ve referans başlatılmadı (veya edildi: Aynı şeyi ifade kere başlatıldı, ancak artık başlatıldı).
Bu, başvurunun olduğu null
ve bir null
başvuru yoluyla üyelere (yöntemler gibi) erişemeyeceğiniz anlamına gelir . En basit durum:
string foo = null;
foo.ToUpper();
Bu NullReferenceException
, ikinci satıra a atar çünkü işaret eden ToUpper()
bir string
başvuruda örnek yöntemini çağıramazsınız null
.
A'nın kaynağını nasıl buldunuz NullReferenceException
? Bunun dışında meydana yerde tam olarak atılacaktır istisna kendisi bakarak, Visual Studio'da hata ayıklama genel kurallar geçerlidir: yer stratejik kesme noktaları ve sizin değişkenleri inceleyin , ya bir (açılış, isimleri üzerine fare gelerek Hızlı) Pencereyi izleyin veya Locals ve Autos gibi çeşitli hata ayıklama panellerini kullanın.
Referansın nerede ayarlandığını veya ayarlanmadığını öğrenmek istiyorsanız, adını sağ tıklayın ve "Tüm Referansları Bul" u seçin. Daha sonra bulunan her konuma bir kesme noktası yerleştirebilir ve hata ayıklayıcı eklenmiş olarak programınızı çalıştırabilirsiniz. Hata ayıklayıcı böyle bir kesme noktasını her kırdığında, başvurunun boş olmamasını bekleyip beklemediğinizi belirlemeniz, değişkeni denetlemeniz ve beklediğinizde bir örneği gösterdiğini doğrulamanız gerekir.
Program akışını bu şekilde izleyerek, örneğin null olmaması gereken konumu ve neden düzgün ayarlanmadığını bulabilirsiniz.
İstisnanın atılabileceği bazı yaygın senaryolar:
ref1.ref2.ref3.member
Ref1 veya ref2 veya ref3 boşsa, bir NullReferenceException
. Sorunu çözmek istiyorsanız, ifadeyi daha basit eşdeğerine yeniden yazarak hangisinin boş olduğunu 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
özelliği null olabilir veya Identity
özelliği null olabilir.
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.
}
}
Alt (Kişi) null başvurusundan kaçınmak isterseniz, üst öğe (Kitap) nesnesinin yapıcısında başlatabilirsiniz.
Aynı şey iç içe nesne başlatıcıları için de geçerlidir:
Book b1 = new Book
{
Author = { Age = 45 }
};
Bu şu anlama gelir
Book b1 = new Book();
b1.Author.Age = 45;
İken new
anahtar kullanılır, sadece yeni bir örneğini oluşturur Book
yeni bir örneğini değil, Person
bu yüzden, Author
mülkiyet hala null
.
public class Person
{
public ICollection<Book> Books { get; set; }
}
public class Book
{
public string Title { get; set; }
}
Yuvalanmış koleksiyon Initializers
aynı şekilde davranır:
Person p1 = new Person
{
Books = {
new Book { Title = "Title1" },
new Book { Title = "Title2" },
}
};
Bu şu anlama gelir
Person p1 = new Person();
p1.Books.Add(new Book { Title = "Title1" });
p1.Books.Add(new Book { Title = "Title2" });
new Person
Sadece bir örneğini oluşturur Person
, ancak Books
koleksiyon hala null
. Koleksiyon Initializer
sözdizimi için bir koleksiyon oluşturmaz p1.Books
, yalnızca p1.Books.Add(...)
ifadelere çevrilir .
int[] numbers = null;
int n = numbers[0]; // numbers is null. There is no array to index.
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.
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.
Dictionary<string, int> agesForNames = null;
int age = agesForNames["Bob"]; // agesForNames is null.
// There is no Dictionary to perform the lookup.
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.
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
}
}
###Bad Naming Conventions:
If you named fields differently from locals, you might have realized that you never initialized the field.
kamu sınıfı Form1 {özel Müşteri müşterisi;
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, alanların alt çizgi ile önek konulması kuralına uyularak çözülebilir:
private Customer _customer;
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!";
}
}
// if the "FirstName" session value has not yet been set,
// then this line will throw a NullReferenceException
string firstName = Session["FirstName"].ToString();
Bir özelliğini başvuran istisnası oluşursa @Model
bir in ASP.NET MVC View
, bunu anlamamız gerekir Model
, eylem yönteminde belirlenen aldığında size return
bir görünümü. Denetleyicinizden boş bir model (veya model özelliği) döndürdüğünüzde, istisna görünümler eriştiğinde gerçekleşir:
// 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
arama sırasında InitializeComponent
görsel ağaçta göründükleri sırayla kontroller oluşturulur . Bir NullReferenceException
yangın sırasında vs. olay işleyicileri, erken oluşturulan kontrollerin durumunda yükseltilecek InitializeComponent
geç oluşturulan denetimleri hangi 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 yaratılmış label1
. Eğer comboBox1_SelectionChanged
referans `label1 girişimleri, henüz oluşturulmuş olmayacaktır.
private void comboBox1_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
label1.Content = comboBox1.SelectedIndex.ToString(); // NullReference here!!
}
XAML
(Yani, daha label1
önce listeleme comboBox1
, tasarım felsefesi meselelerini görmezden gelme) içindeki bildirimlerin sırasını değiştirmek en azından NullReferenceException
burada çözecektir .
as
var myThing = someObject as Thing;
Bu bir atmaz, InvalidCastException
ancak null
döküm başarısız olduğunda (ve someObject
kendisi null olduğunda) a değerini döndürür . Öyleyse bunun farkında olun.
FirstOrDefault()
veSingleOrDefault()
Düz sürümler First()
ve Single()
hiçbir şey olmadığında istisnalar atın. "OrDefault" sürümleri bu durumda null değerini döndürür. Öyleyse bunun farkında olun.
foreach
null koleksiyonu yinelemeye çalıştığınızda atar. Genellikle null
koleksiyonları döndüren yöntemlerden beklenmeyen sonuçlardan kaynaklanır.
List<int> list = null;
foreach(var v in list) { } // exception
Daha gerçekçi bir örnek - XML belgesinden düğümleri seçin. Düğümler bulunmaz, ancak ilk hata ayıklama tüm özelliklerin geçerli olduğunu gösterirse atar:
foreach (var node in myData.MyXml.DocumentNode.SelectNodes("//Data"))
null
Null değerleri açıkça kontrol edin ve yok sayın.Referansın bazen null olmasını bekliyorsanız, null
örnek üyelerine erişmeden önce referansın olup olmadığını kontrol edebilirsiniz :
void PrintName(Person p)
{
if (p != null)
{
Console.WriteLine(p.Name);
}
}
null
Varsayılan değeri açıkça kontrol edin ve sağlayın.Bir örnek döndürmeyi beklediğiniz yöntemler null
, örneğin aranan nesne bulunamadığında dönebilir . Bu durumda varsayılan bir değer döndürmeyi seçebilirsiniz:
string GetCategory(Book b)
{
if (b == null)
return "Unknown";
return b.Category;
}
null
Yöntem çağrılarından açıkça kontrol edin ve özel bir istisna atın.Ayrıca, yalnızca arama kodunda yakalamak için özel bir istisna atayabilirsiniz:
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;
}
Debug.Assert
değeri olmamalıdır eğer null
sorun daha erken durum oluşur daha yakalamak için.Geliştirme sırasında bir yöntemin belki de geri dönebileceğini null
, ancak asla geri dönmemesi gerektiğini bildiğinizde Debug.Assert()
, gerçekleştiğinde mümkün olan en kısa sürede kırmak için kullanabilirsiniz :
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 sürüm derlemenizde bitmeyecek olsa da, sürümde çalışma modundayken NullReferenceException
tekrar atmasına neden olur book == null
.
GetValueOrDefault()
için kullanın .nullable
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
??
[C #] veya If()
[VB].A null
ile karşılaşıldığında varsayılan bir değer sağlama kısayolu :
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;
}
?.
veya ?[x]
diziler için (C # 6 ve VB.NET 14'te bulunur):Buna bazen güvenli navigasyon veya Elvis (şeklinden sonra) operatörü de denir. Operatörün sol tarafındaki ifade null ise, sağ taraf değerlendirilmez ve bunun yerine null döndürülür. Bu, şu gibi durumlar anlamına gelir:
var title = person.Title.ToUpper();
Kişinin bir başlığı yoksa, ToUpper
null değeri olan bir özelliği çağırmaya çalıştığı için bu bir istisna atar .
İçinde C# 5
ve altında, bu ile korunabilir:
var title = person.Title == null ? null : person.Title.ToUpper();
Şimdi istisna atmak yerine title değişkeni null olur. C # 6 bunun için daha kısa bir sözdizimi sunar:
var title = person.Title?.ToUpper();
Bu başlık değişkenin neden olacaktır null
ve arama için ToUpper
eğer yapılmaması person.Title
olduğunu null
.
Elbette, varsayılan bir değer sağlamak için halatitle
null değerini kontrol etmeniz veya null koşul operatörünü (null birleştirme operatörü ( ??
) ile birlikte kullanmanız gerekir :
// 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 ?[i]
aşağıdaki gibi kullanabilirsiniz :
int[] myIntArray=null;
var i=5;
int? elem = myIntArray?[i];
if (!elem.HasValue) Console.WriteLine("No value");
Bu, aşağıdakileri yapacaktır: myIntArray
null ise, ifade null değerini döndürür ve güvenle denetleyebilirsiniz. Bir dizi içeriyorsa: elem = myIntArray[i];
ile aynı işlemi yapar
ve i<sup>th</sup>
öğeyi döndürür .
Burada tanıtılan C# 8
null bağlamın ve null olabilecek referans türleri değişkenler üzerinde statik analiz yapar ve bir değer potansiyel olarak null veya null olarak ayarlanmışsa derleyici uyarısı sağlar. Null edilebilir başvuru türleri, türlerin açıkça boş olmasına izin verilir.
Null olabilecek ek açıklama bağlamı ve nullable uyarı bağlamı, dosyanızdaki Nullable
öğeyi kullanan bir proje için ayarlanabilir csproj
. Bu öğe, derleyicinin türlerin geçersizliğini ve hangi uyarıların üretileceğini nasıl yorumlayacağını yapılandırır. Geçerli ayarlar:
Null olabilecek değer türleriyle aynı sözdizimi kullanılarak null olabilecek bir başvuru türü not edilir: ?
değişkenin türüne a eklenir.
C#
"yineleyici blokları" (diğer bazı popüler dillerde "jeneratörler" olarak adlandırılır) destekler. Boş dereference istisnaları, ertelenmiş yürütme nedeniyle yineleyici bloklarında 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
o MakeFrob
zaman atar. Şimdi, yapılacak doğru şeyin bu olduğunu düşünebilirsiniz:
// 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 blok aslında olmadığından çalıştırmak kadar foreach
! Çağırma çağrısı , yinelendiğinde yineleyici bloğunu çalıştıracak GetFrobs
bir nesne döndürür .
Bu şekilde null bir denetim yazarak null dereference'ı önlersiniz, ancak null argüman istisnasını yineleme noktasına değil, çağrının noktasına taşırsınız ve bu hata ayıklamak çok kafa karıştırıcıdır .
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 null kontrolü yapan ve yineleyiciyi döndüren bir ortak yüzey yöntemi yapın. Şimdi GetFrobs
çağrıldığında, null kontrolü hemen gerçekleşir ve ardından GetFrobsForReal
dizi yinelendiğinde yürütülür.
LINQ
Nesneler için referans kaynağını incelerseniz, bu tekniğin baştan sona kullanıldığını göreceksiniz. Yazmak biraz daha karmaşıktır, ancak hata ayıklama hata hatalarını çok daha kolay hale getirir. Kodunuzu, yazarın rahatlığı için değil, arayanın rahatlığı için optimize edin .
C#
bellek güvenliğini ve tip güvenliğini sağlayan normal emniyet mekanizmaları uygulanmadığından, adından da anlaşılacağı üzere, "güvensiz" bir moda sahiptir. Belleğin nasıl çalıştığını tam ve derin bir şekilde anlamadığınız sürece güvenli olmayan kod yazmamalısınız .
Güvenli olmayan modda, iki önemli gerçeğin farkında olmalısınız:
Bunun nedenini anlamak için, .NET'in ilk olarak nasıl boş dereference istisnaları ürettiğini anlamaya yardımcı olur. (Bu ayrıntılar Windows üzerinde çalışan .NET için geçerlidir; diğer işletim sistemleri benzer mekanizmalar kullanır.)
Bellek sanallaştırılır Windows
; her işlem, işletim sistemi tarafından izlenen birçok "sayfa" belleğin sanal bellek alanına sahip olur. Belleğin her sayfasında, nasıl kullanılabileceğini belirleyen işaretler bulunur: okuma, yazma, yürütme vb. En düşük sayfa "herhangi bir şekilde kullanılıyorsa hata üret" olarak işaretlenir.
Hem null işaretçi hem de null referans C#
dahili olarak sıfır sayısı olarak temsil edilir ve bu nedenle karşılık gelen bellek deposuna atılmak için yapılan her girişim, işletim sisteminde bir hataya neden olur. Sonra .NET çalışma zamanı bu hatayı algılar ve null dereference istisnasına dönüştürür.
Bu nedenle, hem boş gösterici hem de boş bir başvurunun kayıttan çıkarılması aynı istisnayı oluşturur.
İkinci nokta ne olacak? Dereferencing herhangi bir sanal bellek düşük sayfasında düşüyor geçersiz işaretçi aynı işletim sistemi hatası ve böylece aynı duruma neden olur.
Bu neden mantıklı? Diyelim ki iki int içeren bir yapımız ve null değerine eşit yönetilmeyen bir işaretçi var. Eğer yapıdaki ikinci int'den vazgeçmeye CLR
çalışırsak, sıfır noktasına depolamaya erişmeye çalışmaz; depolama alanına dördüncü konumdan erişir. Ama mantıklı olarak bu bir boş dereference çünkü bu adrese null üzerinden ulaşıyoruz.
Güvenli olmayan kodla çalışıyorsanız ve boş bir kural dışı durum istisnası alıyorsanız, rahatsız edici işaretçinin boş olması gerekmediğini unutmayın. En alt sayfada herhangi bir yer olabilir ve bu istisna üretilecektir.
NullReference Exception
İçin Visual Basic içinde birinden farklı değil C # . Sonuçta, her ikisi de kullandıkları .NET Framework'te tanımlanan aynı özel durumu bildiriyorlar. Visual Basic'e özgü nedenler nadirdir (belki de sadece bir tane).
Bu yanıt Visual Basic terimlerini, sözdizimini ve bağlamı kullanacaktır. Kullanılan örnekler çok sayıda geçmiş Stack Overflow sorusundan gelmektedir. Bu, yazılarda sıklıkla görülen durum türlerini kullanarak alaka düzeyini en üst düzeye çıkarmaktır . İhtiyaç duyanlar için biraz daha açıklama da yapılır. Sizinkine benzer bir örneği olduğu çok muhtemeldir burada listelenen.
Not:
NullReferenceException
(NRE) neyin neden olduğunu, nasıl bulunacağını, nasıl düzeltileceğini ve nasıl önleneceğini anlamanıza yardımcı olmak için tasarlanmıştır . Bir NRE'ye birçok yol neden olabilir, bu yüzden bunun tek karşılaşmanız olma ihtimali düşüktür."Nesne bir Nesne örneğine ayarlanmadı" iletisi , başlatılmamış bir nesneyi kullanmaya çalıştığınız anlamına gelir. Bu aşağıdakilerden birine dayanır:
Sorun bir nesne referansı olduğu için Nothing
, cevap hangisini bulmak için onları incelemektir. Ardından neden başlatılmadığını belirleyin. Fareyi çeşitli değişkenlerin üzerinde tutun ve Visual Studio (VS) değerlerini gösterecektir - suçlu olacak Nothing
.
Ayrıca, Try / Catch bloklarını, özellikle Catch bloğunda hiçbir şeyin olmadığı kodları da ilgili koddan kaldırmalısınız. Bu, kodunuz olan bir nesneyi kullanmaya çalıştığında çökmesine neden olur Nothing
. Bu ne istediğiniz o kesin belirleyecektir çünkü konumu sorunu ve bunu neden nesneyi tanımlamak için izin verir.
Görüntülenen MsgBox
Yakalama'daki A Error while...
çok yardımcı olacaktır. Bu yöntem aynı zamanda çok kötü Yığın Taşması sorularına da yol açar , çünkü gerçek istisnayı, dahil olan nesneyi veya hatta gerçekleştiği kod satırını tanımlayamazsınız.
Nesnelerinizi incelemek için Locals Window
( Hata Ayıkla -> Windows -> Yerel Ayarlar ) öğesini de kullanabilirsiniz .
Sorunun ne olduğunu ve nerede olduğunu öğrendikten sonra, yeni bir soru göndermekten genellikle düzeltilmesi oldukça kolaydır.
Ayrıca bakınız:
Dim reg As CashRegister
...
TextBox1.Text = reg.Amount ' NRE
Sorun, Dim
bir CashRegister nesnesi oluşturmamasıdır ; yalnızca reg
bu Tür adlı bir değişkeni bildirir . Bir nesne değişkenini bildirmek ve bir örnek oluşturmak iki farklı şeydir.
çare
New
Operatör sıklıkla beyan zaman örneğini oluşturmak için kullanılabilir:
Dim reg As New CashRegister ' [New] creates instance, invokes the constructor
' Longer, more explicit form:
Dim reg As CashRegister = New CashRegister
Yalnızca daha sonra örneği oluşturmak uygun olduğunda:
Private reg As CashRegister ' Declare
...
reg = New CashRegister() ' Create instance
Not: Do not kullanmak Dim
yapıcısı (dahil olmak üzere bir prosedür tekrar Sub New
):
Private reg As CashRegister
'...
Public Sub New()
'...
Dim reg As New CashRegister
End Sub
Bu, yalnızca bu bağlamda (alt) bulunan yerel bir değişken oluşturur reg
. Diğer her yerde kullanacağınız reg
modül seviyeli değişken Scope
kalır Nothing
.
İşlecin eksik
New
olması,NullReference Exceptions
incelenen Yığın Taşması sorularında görülen 1 numaralı nedendir .Visual Basic işlemi kullanarak tekrar tekrar netleştirmeye çalışır
New
:New
Operator kullanarak yeni bir nesne oluşturur veSub New
nesnenin başka bir başlatma gerçekleştirebilirsiniz - yapıcı - çağırır .
Açık olmak gerekirse, Dim
(veya Private
) yalnızca bir değişkeni ve değişkenini bildirirType
. Kapsam Bu, tüm modülü / sınıf için var olan ya da bir prosedür yerel olup - - değişken belirlenir burada bu ilan edilir. Private | Friend | Public
erişim düzeyini değil, tanımlar Kapsam .
Daha fazla bilgi için, bkz:
Diziler de somutlaştırılmalıdır:
Private arr as String()
Bu dizi yalnızca bildirildi, oluşturulmadı. 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: Değişmez kullanarak yerel bir dizi başlatma ve zaman VS 2010 ile başlayarak, 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ılır. Sınıf / Modül düzeyinde bildirimleri hala gerektirir As <Type>
ile Option Strict
:
Private myDoubles As Double() = {1.5, 2, 9.9, 18, 3.14}
Örnek: Sınıf nesneleri 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 içindeki Foo
nesneler oluşturulmadı .
çare
For i As Integer = 0 To arrFoo.Count - 1
arrFoo(i) = New Foo() ' Create Foo instance
arrFoo(i).Bar = i * 10
Next
Bir List(Of T)
irade kullanmak, geçerli bir nesnesi olmayan bir öğeye sahip olmayı oldukça zorlaştıracaktı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, bkz:
Çok sayıda çeşidi olan Listeler, Sözlük vb. .NET koleksiyonlarının da başlatılması veya oluşturulması gerekir.
Private myList As List(Of String)
..
myList.Add("ziggy") ' NullReference
Aynı nedenden ötürü aynı istisnayı elde edersiniz - myList
sadece beyan edildi, ancak hiçbir örnek oluşturulmadı. Çözüm 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, koleksiyon 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 yordam da bir NRE ile sonuçlanır, çünkü barList
yalnızca bildirilir, somutlaştırılmaz. Örneği oluşturmak Foo
aynı zamanda dahili örneği de oluşturmaz barList
. Bunu yapıcıda yapmak niyetinde 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ış:
Public Sub New()
' Creates another barList local to this procedure
Dim barList As New List(Of Bar)
End Sub
Daha fazla bilgi için, bkz. List(Of T)
Sınıf .
Bir NullReference için veritabanları hediyelerle birçok fırsat Çalışma sayıda nesne (olabilir çünkü Command
, Connection
, Transaction
, Dataset
, DataTable
, DataRows
aynı anda kullanımda ....). Not: Hangi veri sağlayıcıyı kullandığınız önemli değildir - MySQL, SQL Server, OleDB, vb. - 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 hiçbir zaman bir örnek oluşturulmadı. Bu DataAdapter
istek mevcut DataSet
olanı doldurur, bir tane oluşturmaz. Bu durumda, ds
yerel bir değişken olduğundan IDE bunun olabileceği konusunda sizi uyarır :
Modül / sınıf düzeyinde bir değişken olarak bildirildiğinde, durumun göründüğü gibi con
, derleyici, nesnenin bir yukarı akış yordamı tarafından oluşturulup oluşturulmadığını 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)
Bir yazım hatası burada bir sorun: Employees
vs Employee
. Hiçbir Orada edildi DataTable
bir nedenle, "Çalışan" yaratılmış adlı NullReferenceException
sonuçlar ulaşmaya çalışıyorsunuz. Başka bir potansiyel sorun, Items
SQL bir WHERE yantümcesi içerdiğinde böyle olmayacağını varsayar .
çare
Bu bir tablo kullandığından, kullanmak Tables(0)
yazım hatalarını önler. İnceleme 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
Rows
etkilenenlerin sayısını döndüren ve test edilebilen bir işlevdir :
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ğlayacaktır TableNames
önceki örnekte görüldüğü gibi, ancak, SQL veya veritabanı tablosundan ayrıştırma isimleri yapar değil. Sonuç olarak, ds.Tables("TICKET_RESERVATION")
varolmayan bir tabloya başvurur.
Çözüm endeksine göre tablo başvurusu, aynıdır:
If ds.Tables(0).Rows.Count > 0 Then
Ayrıca bkz . DataTable Sınıfı .
If myFoo.Bar.Items IsNot Nothing Then
...
Kod sadece Items
her ikisinde de test ediyor myFoo
ve Bar
hiçbir şey olmayabilir. İlaç , bir anda tüm zincirli veya nesne, bir yolunu test etmektir:
If (myFoo IsNot Nothing) AndAlso
(myFoo.Bar IsNot Nothing) AndAlso
(myFoo.Bar.Items IsNot Nothing) Then
....
AndAlso
önemli. İlk False
koşulla karşılaşıldığında sonraki testler yapılmayacaktır . Bu, kodun nesnelere / nesnelere her seferinde bir 'seviye' güvenli bir şekilde 'delmesini' sağlar ve myFoo.Bar
yalnızca sonra (ve) myFoo
geçerli olduğu belirlenir. Karmaşık nesneleri kodlarken nesne zincirleri veya yolları oldukça uzun sürebilir:
myBase.myNodes(3).Layer.SubLayer.Foo.Files.Add("somefilename")
Bir null
nesnenin 'akış aşağısına' herhangi bir şey referans vermek mümkün değildir . Bu aynı zamanda kontroller için de geçerlidir:
myWebBrowser.Document.GetElementById("formfld1").InnerText = "some value"
Burada, myWebBrowser
ya Document
da Hiçbir şey olabilir ya da formfld1
öğe olmayabilir.
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 şeylerin yanı sıra, bu kod kullanıcının bir veya daha fazla UI kontrolünde bir şey seçmemiş olabileceğini öngörmez. ListBox1.SelectedItem
olabilir Nothing
, bu nedenle ListBox1.SelectedItem.ToString
bir NRE ile sonuçlanacaktır.
çare
Kullanmadan önce verileri doğrulayın (ayrıca Option Strict
ve SQL parametrelerini de kullanın ):
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, (ComboBox5.SelectedItem IsNot Nothing) AndAlso...
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 elde etmenin oldukça yaygın bir yoludur. C # 'da, nasıl kodlandığına bağlı olarak, IDE Controls
geçerli bağlamda bulunmadığını veya "statik olmayan üyeye başvuramayacağını" bildirecektir . Yani, bir dereceye kadar, bu sadece bir VB durumudur. Aynı zamanda karmaşıktır, çünkü bir başarısızlık kaskatına neden olabilir.
Diziler ve koleksiyonlar bu şekilde başlatılamaz. Bu başlatma kodu , yapıcı veya öğesini oluşturmadan önce çalışır . Sonuç olarak:Form
Controls
somevar
Hiçbir şey bir sahip olmadığı için atama acil NRE neden olacaktır .Text
özelliğiDizi öğelerine daha sonra başvurmak bir NRE ile sonuçlanır. Bu in yaparsanız Form_Load
nedeniyle garip bir hatadan, IDE olmayabilir o olur istisna raporu. Kodunuz diziyi kullanmaya çalıştığında istisna daha sonra açılır . Bu "sessiz istisna" bu yayında detaylandırılmıştır . Bizim amacımız için anahtar, bir form ( Sub New
veya Form Load
olay) oluştururken felaket bir şey olduğunda , istisnalar bildirilmeyebilir, kod prosedürden çıkar ve sadece formu görüntüler.
NRE'den sonra etkinliğinizde Sub New
veya Form Load
etkinliğinizde başka hiçbir kod çalışmadığından, pek çok başka şey başlatılmadan bırakılabilir.
Sub Form_Load(..._
'...
Dim name As String = NameBoxes(2).Text ' NRE
' ...
' More code (which will likely not be executed)
' ...
End Sub
Bunun, bunları yasadışı oldukları yerlerde yapan tüm kontrol ve bileşen referansları için geçerli olduğunu unutmayın :
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 bir uyarı sağlamaz meraklı olmakla çare olmaktır beyan formu düzeyinde kapları, ancak başlatmak kontrolleri yaparken form yük olay işleyicisi bunları yapmak vardır. Bu, Sub New
kodunuz InitializeComponent
çağrıdan sonra olduğu sürece yapılabilir :
' 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 orman dışında olmayabilir. Bir konteyner kontrolünde olan kontroller (a GroupBox
veya gibi Panel
) içinde bulunmaz Me.Controls
; bu Panel veya GroupBox öğesinin Kontroller koleksiyonunda olacaklardır. Kontrol adı yanlış yazıldığında ( "TeStBox2"
) da bir kontrol döndürülmez . Bu gibi durumlarda, Nothing
yine bu dizi öğelerinde saklanır ve referans vermeye çalıştığınızda bir NRE oluşur.
Ne aradığınızı bildiğiniz için bunları bulmak kolay olmalıdır:
"Button2", Panel
çare
Formun Controls
koleksiyonunu kullanarak ada göre dolaylı başvurular yerine , denetim başvurusunu 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...})
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 ' tüm yolların bir değer döndürmediği ve bir NullReferenceException
sonucun ortaya çıkabileceği ' konusunda sizi uyaracağı bir durumdur . Sen değiştirerek, uyarıyı bastırmak Exit Function
ile Return Nothing
, ama bu sorunu çözmez. Ne zaman dönüşü kullanmaya çalışan herhangi bir şey someCondition = False
NRE ile sonuçlanır:
bList = myFoo.BarList()
For Each b As Bar in bList ' EXCEPTION
...
çare
İşlevdeki Exit Function
ile değiştirin Return bList
. Bir dönersek boş List
dönen aynı şey değildir Nothing
. Döndürülen bir nesnenin olma şansı varsa Nothing
, kullanmadan önce test edin:
bList = myFoo.BarList()
If bList IsNot Nothing Then...
Kötü uygulanan Try / Catch, sorunun nerede olduğunu gizleyebilir ve yenileriyle 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 yaratılmayan bir nesnenin örneğidir, ancak boş bir nesnenin karşı kullanışlılığını da gösterir Catch
.
SQL'de ('mailaddress' den sonra) 'da bir istisna ile sonuçlanan fazladan bir virgül vardır .ExecuteReader
. Catch
Hiçbir şey yapmadan sonra, Finally
temizlemeyi yapmaya çalışır, ancak Close
boş bir DataReader
nesne olamayacağınız için yepyeni bir NullReferenceException
sonuç elde edersiniz .
Boş bir Catch
blok şeytanın oyun alanıdır. Bu OP, neden Finally
blokta bir NRE aldığını şaşırttı . Diğer durumlarda, boş Catch
bir şey daha aşağı akış yönünde başka bir şeyle sonuçlanabilir ve sorun için yanlış yere yanlış şeylere bakmak için zaman harcamanıza neden olabilir. (Yukarıda açıklanan "sessiz istisna" aynı eğlence değerini sağlar.)
çare
Boş Try / Catch blokları kullanmayın - kodun çökmesine izin verin, böylece a) nedenini tanımlayın b) konumu belirleyin ve c) uygun bir çözüm uygulayın. Try / Catch blokları, bunları düzeltmek için benzersiz nitelikteki kişiden istisnaları gizlemek için tasarlanmamıştır - geliştirici.
For Each row As DataGridViewRow In dgvPlanning.Rows
If Not IsDBNull(row.Cells(0).Value) Then
...
IsDBNull
Bir IF_FUNCTION testi için kullanılan değer eşittir System.DBNull
: MSDN:
System.DBNull değeri, Object'in eksik veya var olmayan verileri temsil ettiğini gösterir. DBNull, bir değişkenin henüz başlatılmadığını gösteren Hiçbir Şey ile aynı değildir.
çare
If row.Cells(0) IsNot Nothing Then ...
Daha önce olduğu gibi, Hiçbir şey 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
Nothing
referans türleri için olan ve asla DBNull
: ilk öğeyi veya varsayılan değeri döndürür :
If getFoo IsNot Nothing Then...
Dim chk As CheckBox
chk = CType(Me.Controls(chkName), CheckBox)
If chk.Checked Then
Return chk
End If
A CheckBox
ile chkName
bulunamazsa (veya a'da mevcutsa GroupBox
), chk
Hiçbir şey olmaz ve herhangi bir özelliğe başvurmaya çalışmak istisnaya neden olur.
çare
If (chk IsNot Nothing) AndAlso (chk.Checked) Then ...
DGV'nin periyodik olarak görülen birkaç tuhaflığı var:
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"
Varsa dgvBooks
, AutoGenerateColumns = True
sütunları oluşturur, ancak bunları adlandırmaz, bu nedenle yukarıdaki kod, ada göre başvurduğunda başarısız olur.
çare
Sütunları manuel olarak adlandırın veya dizine göre başvuru yapın:
dgvBooks.Columns(0).Visible = True
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
When DataGridView
sahip AllowUserToAddRows
olarak True
(varsayılan), Cells
altta işlenmemiş / yeni satır tümünü içerir Nothing
. İçeriği (ör. ToString
) Kullanma girişimlerinin çoğu NRE ile sonuçlanır.
çare
Bir For/Each
döngü kullanın ve IsNewRow
son satır olup olmadığını belirlemek için özelliği test edin . Bu AllowUserToAddRows
doğru olsun ya da olmasın çalışır :
For Each r As DataGridViewRow in myDGV.Rows
If r.IsNewRow = False Then
' ok to use this row
Bir For n
döngü kullanıyorsanız , satır sayısını değiştirin veya true Exit For
olduğunda kullanın IsNewRow
.
Belirli koşullar altında, bir öğeyi kullanmaya çalışıyor My.Settings
bir olan StringCollection
bir NullReference içinde bunu kullanmak ilk defa sonuçlanabilir. Çözüm aynı, ancak belli değil. Düşünmek:
My.Settings.FooBars.Add("ziggy") ' foobars is a string collection
VB sizin için Ayarlar'ı yönettiği için koleksiyonun başlatılmasını beklemek mantıklıdır. Ancak, koleksiyona daha önce bir başlangıç girdisi eklediyseniz (Ayarlar düzenleyicisinde). Bir öğe eklendiğinde koleksiyon (görünüşte) başlatıldığından, eklenecek Nothing
Ayarlar düzenleyicisinde hiçbir öğe olmadığında kalır .
çare
Load
Gerekirse / gerektiğinde, formun olay işleyicisindeki ayarlar koleksiyonunu başlatın :
If My.Settings.FooBars Is Nothing Then
My.Settings.FooBars = New System.Collections.Specialized.StringCollection
End If
Genellikle, Settings
koleksiyonun yalnızca uygulama ilk çalıştırıldığında başlatılması gerekir. Alternatif bir çözüm, Project -> Ayarlar | FooBars , projeyi kaydedin, sonra sahte değeri kaldırın.
Muhtemelen New
operatörü unuttun .
veya
Başlatılan bir nesneyi kodunuza döndürmek için sorunsuz bir şekilde gerçekleştireceğinizi varsaydığınız bir şey olmadı.
Derleyici uyarılarını (hiç) dikkate almayın ve Option Strict On
(her zaman) kullanmayın .
Başka bir senaryo, null bir nesneyi bir değer türüne attığınız durumdur . Örneğin, aşağıdaki kod:
object o = null;
DateTime d = (DateTime)o;
Bu bir atacağım NullReferenceException
döküm üzerinde. Yukarıdaki örnekte oldukça açık görünmektedir, ancak bu, null nesnesinin sahip olmadığınız bazı kodlardan döndürüldüğü ve dökümün örneğin bazı otomatik sistem tarafından oluşturulduğu daha "geç bağlayıcı" karmaşık senaryolarda olabilir.
Bunun bir örneği bu basit ASP.NET bağlama parçasını Takvim denetimi ile:
<asp:Calendar runat="server" SelectedDate="<%#Bind("Something")%>" />
Burada, SelectedDate
bir - bir özellik aslında DateTime
tip - ait Calendar
Web Kontrol türü ve mükemmel bir şey return null olabilir bağlayıcı. Örtülü ASP.NET Generator yukarıdaki döküm koduna eşdeğer olacak bir kod parçası oluşturur. Ve bu NullReferenceException
ince bir derleyen ASP.NET oluşturulan kod yatıyor çünkü, bu oldukça zor bir nokta yükseltir ...
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Bu, söz konusu değişkenin hiçbir şeye işaret etmediği anlamına gelir. Ben böyle üretebilir:
SqlConnection connection = null;
connection.Open();
Bu hatayı atacak çünkü " connection
" değişkenini beyan ederken , hiçbir şeye işaret etmiyor. " Open
" Adlı üyeyi aramaya çalıştığımda , çözümlemesi için bir referans yok ve hatayı atacak.
Bu hatayı önlemek için:
object == null
.JetBrains 'Resharper aracı, kodunuzda bir boş başvuru hatası olasılığı bulunan her yeri tanımlar ve boş bir denetim gerçekleştirmenize olanak tanır. Bu hata bir numaralı hata kaynağıdır, IMHO.
Kodunuzun, null olarak ayarlanmış bir nesne başvuru değişkeni kullandığı (yani, gerçek bir nesne örneğine başvurmadığı) anlamına gelir.
Hatayı önlemek için null olabilecek nesneler kullanılmadan önce null için 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
}
Senaryoya bakılmaksızın, nedenin .NET'te her zaman aynı olduğunu unutmayın:
Değeri
Nothing
/ olan bir başvuru değişkeni kullanmaya çalışıyorsunuznull
. Değer, başvuru değişkeni içinNothing
/ olduğundanull
, bu aslında yığın üzerinde var olan herhangi bir nesnenin örneğine bir başvuru tutmadığı anlamına gelir.Ya değişkene atanan değerin bir örneğini oluşturdu asla değişkene şey atanan asla veya değişkeni ayarlamak için eşit
Nothing
/null
manuel veya değişkeni ayarlamak bir işlevi olarak adlandırılanNothing
/ 'null
senin için.
Atılan bu istisnanın bir örneği: Bir şeyi kontrol etmeye çalıştığınızda, bu boştur.
Ö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ı, başlatılmamış bir şey üzerinde bir eylem gerçekleştirmeye çalıştığınızda (örn. Yukarıdaki kod) bir NullReferenceException kurar.
Bir yöntem kendisine iletilen şeyin null olmadığını beklerse, genellikle bir savunma ölçüsü olarak atılan bir ArgumentNullException özelliğine kıyasla.
Daha fazla bilgi için C # NullReferenceException ve Null Parametreleri bulunur .
Güncelleme C # 8.0, 2019: Null olabilecek referans türleri
C # 8.0 nullable referans türleri ve nullable referans türleri sunar . Bu nedenle, NullReferenceException özel durumundan kaçınmak için yalnızca boş değerli başvuru türlerinin denetlenmesi gerekir .
Bir başvuru türünü başlatmadıysanız ve özelliklerinden birini ayarlamak veya okumak istiyorsanız, bir NullReferenceException kurar .
Misal:
Person p = null;
p.Name = "Harry"; // NullReferenceException occurs here.
Değişkenin boş olup olmadığını kontrol ederek bunu önleyebilirsiniz:
Person p = null;
if (p!=null)
{
p.Name = "Harry"; // Not going to run to this point
}
NullReferenceException özelliğinin neden atıldığını tam olarak anlamak için, değer türleri ile [başvuru türleri] arasındaki farkı bilmek önemlidir [3].
Uğraştığın Yani, değer türleri , NullReferenceExceptions olabilir değil oluşabilir. Referans türleriyle uğraşırken uyanık olmanız gerekir !
Yalnızca adın önerdiği gibi referans türleri referansları tutabilir veya tam anlamıyla hiçbir şeye (veya 'null') işaret edebilir. Oysa değer türleri her zaman bir değer içerir.
Referans türleri (bunlar kontrol edilmelidir):
Değer türleri (bunları göz ardı edebilirsiniz):
NullReferenceExceptions
Olabilecek başka bir durum , as
operatörün (yanlış) kullanımıdır :
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
Burada Book
ve Car
uyumsuz türler; a Car
dönüştürülemez / a dönüştürülemez Book
. Bu yayın başarısız olduğunda as
geri döner null
. Bundan mybook
sonra kullanmak a NullReferenceException
.
Genel olarak, bir döküm kullanmalısınız veya as
aşağıdaki gibi:
Tür dönüşümünün her zaman başarılı olmasını bekliyorsanız (yani, nesnenin vaktinden önce ne olması gerektiğini biliyorsanız), bir döküm kullanmalısınız:
ComicBook cb = (ComicBook)specificBook;
Türden emin değilseniz, ancak belirli bir tür olarak kullanmayı denemek istiyorsanız , şunu kullanın as
:
ComicBook cb = specificBook as ComicBook;
if (cb != null) {
// ...
}
Boş değer başvurusunu içeren nesneyi kullanıyorsunuz. Yani boş bir istisna veriyor. Örnekte dize değeri null ve uzunluğunu kontrol ederken kural dışı durum oluştu.
Misal:
string value = null;
if (value.Length == 0) // <-- Causes exception
{
Console.WriteLine(value); // <-- Never reached
}
İstisna hatası:
İşlenmeyen özel durum:
System.NullReferenceException: Nesne başvurusu bir nesnenin örneğine ayarlanmadı. Program.Main () 'da
İken Ne bir sebep NullReferenceExceptions ve yaklaşımları kaçınmak / düzeltmek diğer yanıtlar ele alınmıştır böyle bir istisna, birçok programcı henüz öğrenmemiş ne bağımsız nasıl olduğunu hata ayıklamak gelişimi sırasında bu tür istisnalar.
Visual Studio'da bu genellikle Visual Studio Hata Ayıklayıcısı sayesinde kolaydır .
İlk olarak, doğru hatanın yakalanacağından emin olun - bkz . VS2010'da 'System.NullReferenceException' öğesinin kesilmesine nasıl izin verebilirim? Not 1
Sonra Hata Ayıklama (F5) ile başlayın veya [VS Hata Ayıklayıcı] 'yı Çalıştırma İşlemine ekleyin . Bazen Debugger.Break
hata ayıklayıcıyı başlatmayı isteyecek kullanımı yararlı olabilir .
Şimdi, NullReferenceException özel durumu atıldığında (veya işlenmediğinde) hata ayıklayıcı, özel durumun oluştuğu satırda durur (yukarıda ayarlanan kuralı hatırlıyor musunuz?). Bazen hatanın fark edilmesi kolay olur.
Örneğin, aşağıdaki satırda özel duruma neden olabilecek tek kod myString
null olarak değerlendirilir. Bu, İzleme Penceresine bakarak veya Anlık Pencerede ifadeleri çalıştırarak doğrulanabilir .
var x = myString.Trim();
Aşağıdakiler gibi daha gelişmiş durumlarda, str1
null olup olmadığını veya null olup olmadığını belirlemek için ifadeleri incelemek için yukarıdaki tekniklerden birini (Watch veya Immediate Windows) kullanmanız gerekir str2
.
var x = str1.Trim() + str2.Trim();
İstisnanın atıldığı bir yere yerleştirildikten sonra , null değerin [yanlış] nereye yerleştirildiğini bulmak genellikle geriye doğru muhakeme yapmak önemsizdir -
İstisnanın nedenini anlamak için gereken zamanı ayırın. Boş ifadeler olup olmadığını kontrol edin. Bu tür boş ifadelere yol açmış olabilecek önceki ifadeleri inceleyin. Kesme noktaları ekleyin ve programa uygun şekilde adım atın . Hata ayıklayıcıyı kullanın.
1 Atışlarda Ara çok agresifse ve hata ayıklayıcı, .NET veya 3. taraf kitaplığındaki bir NPE'de durursa, yakalanan istisnaları sınırlamak için Kullanıcı İşlenmemiş Break kullanılabilir. Ayrıca, VS2012, etkinleştirmeyi de tavsiye ettiğim Just My Code'u sunar .
Just My Code etkinken hata ayıklama yapıyorsanız, davranış biraz farklıdır. Kodum etkinken, hata ayıklayıcı Kodumun dışına atılan ve Kodumdan geçmeyen birinci şans ortak dil çalışma zamanı (CLR) istisnalarını yok sayar.
Simon Mourier bu örneği verdi :
object o = null;
DateTime d = (DateTime)o; // NullReferenceException
burada bir kutudan çıkarma dönüşüm (döküm) den object
(veya sınıflarının birinden System.ValueType
veya System.Enum
veya bir arayüz türünden) için (başka bir değer türü Nullable<>
kendi içinde) elde edilir NullReferenceException
.
Diğer yönde, bir boks dönüşüm gelen bir Nullable<>
yer alır HasValue
eşit false
için bir referans tipi, verebilir null
daha sonra bir yol açabilir referans NullReferenceException
. Klasik örnek şöyledir:
DateTime? d = null;
var s = d.ToString(); // OK, no exception (no boxing), returns ""
var t = d.GetType(); // Bang! d is boxed, NullReferenceException
Bazen boks başka bir şekilde olur. Örneğin, bu genel olmayan uzantı yöntemiyle:
public static void MyExtension(this object x)
{
x.ToString();
}
aşağıdaki kod sorunlu olacaktır:
DateTime? d = null;
d.MyExtension(); // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.
Bu durumlar, çalışma zamanının boks Nullable<>
örnekleri için kullandığı özel kurallar nedeniyle ortaya çıkar .
Varlık çerçevesinde kullanılan varlık için sınıf adı, bir web formu kod arkası dosyası için sınıf adıyla aynı olduğunda durum ekleme.
Codebehind sınıfı Contact olan bir iletişim formunuz ve Contact adınız olan bir varlık formunuz olduğunu varsayalım.
Bağlamı çağırdığınızda, aşağıdaki kod bir NullReferenceException özel durumu atar.
Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line
Bütünlük uğruna DataContext sınıfı
public class DataContext : DbContext
{
public DbSet<Contact> Contacts {get; set;}
}
ve Kişi varlık sınıfı. Bazen varlık sınıfları kısmi sınıflardır, böylece bunları başka dosyalarda da genişletebilirsiniz.
public partial class Contact
{
public string Name {get; set;}
}
Hata hem varlık hem de codebehind sınıfı aynı ad alanında olduğunda oluşur. Bunu düzeltmek için, contact.aspx için varlık sınıfını veya codebehind sınıfını yeniden adlandırın.
Sebep hala neden olduğundan emin değilim. Ancak varlık sınıflarından herhangi biri System.Web.UI.Page öğesini genişlettiğinde bu hata oluşur.
Tartışma için DbContext.saveChanges () NullReferenceException bir göz atın
Bir kişinin bu istisnayı alabileceği bir diğer genel durum, birim testi sırasında alay sınıflarını içerir. Kullanılan alaycı çerçeveden bağımsız olarak, sınıf hiyerarşisinin tüm uygun düzeylerinin uygun şekilde alay edildiğinden emin olmalısınız. Özellikle, tüm özellikleri HttpContext
test edilen kod tarafından referans alınan alay edilmelidir.
Biraz ayrıntılı bir örnek için bkz. " Özel AuthorizationAttribute test edilirken atılan " NullReferenceException ".
Buna cevap vermek için farklı bir bakış açım var. Bu tür cevaplar "bundan kaçınmak için başka ne yapabilirim? "
Farklı katmanlar üzerinde çalışırken , örneğin bir MVC uygulamasında, bir denetleyicinin ticari işlemleri çağırmak için hizmetlere ihtiyacı vardır. Bu tür senaryolarda NullReferenceException özel durumundan kaçınmak için hizmetleri başlatmak üzere Bağımlılık Enjeksiyon Kapsayıcısı kullanılabilir . Bu, null olup olmadığını kontrol etme konusunda endişelenmeniz gerekmediği anlamına gelir ve hizmetleri her zaman tek birton veya bir prototip olarak kullanılabilir (ve başlatılmış) gibi denetleyiciden arayın.
public class MyController
{
private ServiceA serviceA;
private ServiceB serviceB;
public MyController(ServiceA serviceA, ServiceB serviceB)
{
this.serviceA = serviceA;
this.serviceB = serviceB;
}
public void MyMethod()
{
// We don't need to check null because the dependency injection container
// injects it, provided you took care of bootstrapping it.
var someObject = serviceA.DoThis();
}
}
" Bu konuda ne yapmalıyım" konusunda birçok cevap olabilir.
Bu tür hata koşullarını geliştirirken önlemenin daha "resmi" bir yolu, kodunuzda sözleşme ile tasarım uygulamaktır . Bu, geliştirirken sınıf değişmezlerini ve / veya hatta işlev / yöntem ön koşullarını ve son koşullarını ayarlamanız gerektiği anlamına gelir .
Kısacası, sınıf değişmezleri , normal kullanımda ihlal almazsınız Sınıfınızdaki bazı kısıtlamalar olacağı (ve dolayısıyla, sınıf olacak sağlamak değil tutarsız bir durumda olsun). Önkoşullar , bir işleve / yönteme girdi olarak verilen verilerin ayarlanan bazı kısıtlamalara uyması ve bunları asla ihlal etmemesi gerektiği anlamına gelir ve önkoşullar , bir işlev / yöntem çıktısının hiçbir zaman ihlal etmeden ayarlanan kısıtlamaları tekrar izlemesi gerektiği anlamına gelir. Sözleşme şartları gerektiğini asla bu nedenle olurken, hata ayıklama modunda pratikte kontrol edilir sözleşme tasarım, bir hata içermeyen bir program yürütülürken ihlal sürümlerde devre dışı gelişmiş sistem performansını maksimize etmek.
Bu şekilde, NullReferenceException
ayarlanan kısıtlamaları ihlal eden durumlardan kaçınabilirsiniz . Örneğin, X
bir sınıfta bir nesne özelliği kullanır ve daha sonra yöntemlerinden birini çağırmayı denerseniz ve X
null değeri varsa, bu aşağıdakilere yol açar NullReferenceException
:
public X { get; set; }
public void InvokeX()
{
X.DoSomething(); // if X value is null, you will get a NullReferenceException
}
Ancak, yöntem önkoşulu olarak "X özelliği hiçbir zaman boş değerli olmamalıdır" değerini ayarlarsanız, daha önce açıklanan senaryoyu önleyebilirsiniz:
//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant ()
{
Contract.Invariant ( X != null );
//...
}
Bu nedenle, .NET uygulamaları için Kod Sözleşmeleri projesi bulunmaktadır.
Alternatif olarak, sözleşme ile tasarım iddialar kullanılarak uygulanabilir .
GÜNCELLEME: Terimin, Eyfel programlama dili tasarımı ile bağlantılı olarak Bertrand Meyer tarafından oluşturulduğunu belirtmek gerekir .
NullReferenceException
Boş bir nesnenin Özelliklerine erişmeye çalıştığımızda veya bir dize değeri boş olduğunda ve dize yöntemlerine erişmeye çalıştığımızda A atılır.
Örneğin:
Boş bir dizenin dize yöntemine erişildiğinde:
string str = string.Empty;
str.ToLower(); // throw null reference exception
Boş bir nesnenin özelliğine erişildiğinde:
Public Class Person {
public string Name { get; set; }
}
Person objPerson;
objPerson.Name /// throw Null refernce Exception
String.Empty.ToLower()
boş bir başvuru istisnası atmaz. Boş da olsa gerçek bir dizeyi temsil eder (yani ""
). Bunun çağrılacak bir nesnesi olduğundan ToLower()
, orada boş bir referans istisnası atmak mantıklı olmaz.
TL; DR: kullanmayı deneyin Html.Partial
yerineRenderpage
Object reference not set to an instance of an object
Bir Görünüm içinde bir Görünüm göndermeye çalıştığımda, şöyle bir Model göndererek alıyordum :
@{
MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null
Hata ayıklama, modelin MyOtherView içinde Null olduğunu gösterdi. Şunu değiştirene kadar:
@{
MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);
Ve işe yaradı.
Ayrıca, Html.Partial
başlamak zorunda kalmamamın nedeni, Visual Studio'nun farklı bir şekilde oluşturulmuş bir döngü içinde olması durumunda bazen hata görünümlü dalgalı çizgiler atmasıydı , çünkü gerçekten bir hata olmasa da:Html.Partial
foreach
@inherits System.Web.Mvc.WebViewPage
@{
ViewBag.Title = "Entity Index";
List<MyEntity> MyEntities = new List<MyEntity>();
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
MyEntities.Add(new MyEntity());
}
<div>
@{
foreach(var M in MyEntities)
{
// Squiggly lines below. Hovering says: cannot convert method group 'partial' to non-delegate type Object, did you intend to envoke the Method?
@Html.Partial("MyOtherView.cshtml");
}
}
</div>
Ama uygulamayı bu "hata" ile sorunsuz çalıştırabildim. foreach
Döngünün yapısını aşağıdaki gibi değiştirerek hatadan kurtulabildim :
@foreach(var M in MyEntities){
...
}
Bir hissim olmasına rağmen, Visual Studio ve işaretleri ve parantezleri yanlış okuduğu için.
Html.Partial
, değil@Html.Partial
Null
), bu yüzden hatanın Modeli nasıl gönderdiğimle ilgili olduğunu biliyordum.
Bu konuda ne yapabilirsiniz?
Burada null referansın ne olduğunu ve nasıl hata ayıklanacağını açıklayan birçok iyi cevap var. Ancak sorunu nasıl önleyeceğiniz veya en azından yakalamayı nasıl kolaylaştıracağınız hakkında çok az şey var.
Bağımsız değişkenleri kontrol edin
Örneğin, yöntemler null olup olmadıklarını görmek için farklı argümanları kontrol edebilir ve ArgumentNullException
bu kesin amaç için açık bir şekilde oluşturulmuş bir istisna a.
Even için yapıcı ArgumentNullException
, parametrenin adını ve bir mesajı argüman olarak alır, böylece geliştiriciye sorunun tam olarak ne olduğunu söyleyebilirsiniz.
public void DoSomething(MyObject obj) {
if(obj == null)
{
throw new ArgumentNullException("obj", "Need a reference to obj.");
}
}
Araçları Kullan
Ayrıca yardımcı olabilecek birkaç kütüphane vardır. Örneğin "Resharper" kodu yazarken, özellikle de özniteliklerini kullanıyorsanız uyarı verebilir : NotNullAttribute
Çalışma Contract.Requires(obj != null)
zamanı ve derleme denetimi sağlayan sözdizimini kullandığınız "Microsoft Kod Sözleşmeleri" vardır : Kod Sözleşmelerini Tanıtma .
Ayrıca, sadece bunun gibi özellikleri kullanmanıza izin verecek "PostSharp" var:
public void DoSometing([NotNull] obj)
Bunu yaparak ve PostSharp'ı oluşturma işleminizin bir parçası haline getirerek obj
çalışma zamanında null olup olmadığını kontrol edin. Bkz. PostSharp null denetimi
Açık Kod Çözümü
Veya her zaman düz eski kodu kullanarak kendi yaklaşımınızı kodlayabilirsiniz. Örneğin, boş referansları yakalamak için kullanabileceğiniz bir yapı. Aynı konseptten sonra modellenmiştir Nullable<T>
:
[System.Diagnostics.DebuggerNonUserCode]
public struct NotNull<T> where T: class
{
private T _value;
public T Value
{
get
{
if (_value == null)
{
throw new Exception("null value not allowed");
}
return _value;
}
set
{
if (value == null)
{
throw new Exception("null value not allowed.");
}
_value = value;
}
}
public static implicit operator T(NotNull<T> notNullValue)
{
return notNullValue.Value;
}
public static implicit operator NotNull<T>(T value)
{
return new NotNull<T> { Value = value };
}
}
Nullable<T>
İzin vermemek için tam tersini başarma amacı dışında, kullandığınız gibi çok benzer şekilde kullanırsınız null
. İşte bazı örnekler:
NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null
NotNull<T>
dolaylı olarak yayınlanır ve T
böylece ihtiyacınız olan her yerde kullanabilirsiniz. Örneğin, bir Person
nesneyi aşağıdakileri alan bir yönteme iletebilirsiniz NotNull<Person>
:
Person person = new Person { Name = "John" };
WriteName(person);
public static void WriteName(NotNull<Person> person)
{
Console.WriteLine(person.Value.Name);
}
Yukarıda nullable ile olduğu gibi görebileceğiniz gibi, Value
özellik üzerinden temel değere erişirsiniz . Alternatif olarak, açık veya kapalı bir kadro kullanabilirsiniz, aşağıdaki dönüş değeri olan bir örnek görebilirsiniz:
Person person = GetPerson();
public static NotNull<Person> GetPerson()
{
return new Person { Name = "John" };
}
Ya da yöntem sadece T
(bu durumda Person
) bir döküm yaparak geri döndüğünde kullanabilirsiniz . Örneğin, aşağıdaki kod aynen yukarıdaki kodu ister:
Person person = (NotNull<Person>)GetPerson();
public static Person GetPerson()
{
return new Person { Name = "John" };
}
Uzantı ile Birleştir
NotNull<T>
Bir uzantı yöntemiyle birleştirin ve daha da fazla durumu kapsayabilirsiniz. Uzantı yönteminin nasıl görünebileceğine ilişkin bir örnek:
[System.Diagnostics.DebuggerNonUserCode]
public static class NotNullExtension
{
public static T NotNull<T>(this T @this) where T: class
{
if (@this == null)
{
throw new Exception("null value not allowed");
}
return @this;
}
}
Ve işte nasıl kullanılabileceğine bir örnek:
var person = GetPerson().NotNull();
GitHub
Referansınız için yukarıdaki kodu GitHub'da kullanılabilir hale getirdim, bulabilirsiniz:
https://github.com/luisperezphd/NotNull
İlgili Dil Özelliği
C # 6.0 bu konuda biraz yardımcı olan "null koşullu işleç" i tanıttı. Bu özellik sayesinde, iç içe geçmiş nesnelere başvurabilirsiniz ve bunlardan herhangi biri varsa null
ifadenin tamamı geri döner null
.
Bu, bazı durumlarda yapmanız gereken boş kontrol sayısını azaltır. Sözdizimi, her noktadan önce bir soru işareti koymaktır. Örneğin, aşağıdaki kodu ele alalım:
var address = country?.State?.County?.City;
Bunun country
, Country
adı verilen bir özelliğe sahip türden bir nesne olduğunu düşünün State
. Eğer country
, State
, County
veya City
olduğu null
daha sonra address will be
boş . Therefore you only have to check whether
adres is
null`.
Harika bir özellik, ancak size daha az bilgi veriyor. 4'ten hangisinin boş olduğu belli değil.
Nullable gibi yerleşik?
C # için güzel bir stenografi vardır Nullable<T>
, böyle bir türden sonra bir soru işareti koyarak nullable bir şey yapabilirsiniz int?
.
C # gibi bir şey olsaydı iyi olurdu NotNull<T>
yukarıda yapı ve belki de benzer işarkadaşı ünlem işareti vardı gibi bir şey yazabilirsiniz ki (!): public void WriteName(Person! person)
.
İlginçtir, bu sayfadaki cevapların hiçbiri iki uç durumdan bahsetmiyor, bunları eklersem kimsenin aklına gelmez:
.NET'teki genel sözlükler iş parçacığı için güvenli değildir ve iki eşzamanlı iş parçacığından bir anahtara erişmeye çalıştığınızda bazen bir NullReference
veya daha sık (daha sık) a atabilirler KeyNotFoundException
. Bu durumda istisna oldukça yanıltıcıdır.
A kodla NullReferenceException
atılırsa unsafe
, işaretçi değişkenlerinize bakabilir ve bunları kontrol edebilirsiniz IntPtr.Zero
. Aynı şey ("boş işaretçi istisnası"), ancak güvenli olmayan kodda, değişkenler genellikle değer türleri / diziler vb. İçin kullanılır ve bir değer türünün bunu nasıl atabileceğini merak ederek başınızı duvara vurursunuz istisna.
(Bu arada, güvenli olmadıkça güvenli olmayan kod kullanmamanın başka bir nedeni)
null
hangi yoldan farklı ?
C # 6'da Null koşullu işleçleri kullanarak NullReferenceException'ı temiz bir şekilde düzeltebilir ve null denetimleri işlemek için daha az kod yazabilirsiniz.
Üye erişimi (?.) Veya dizin (? [) İşlemini gerçekleştirmeden önce null değerini sınamak için kullanılır.
Misal
var name = p?.Spouse?.FirstName;
şuna eşittir:
if (p != null)
{
if (p.Spouse != null)
{
name = p.Spouse.FirstName;
}
}
Sonuç olarak, p boşken veya p boşken ad boş olacaktır.
Aksi takdirde, değişken adına p.Spouse.FirstName değeri atanır.
Daha fazla bilgi için: Koşulsuz Operatörler
"Nesne başvurusu bir nesnenin örneğine ayarlanmadı" hata satırı, nesne nesnesine örnek nesne atamadığınızı ve yine de o nesnenin properies / yöntemlerine eriştiğinizi belirtir.
örneğin: myClass adında bir sınıfınız olduğunu ve bir tane prop1 özelliği içerdiğini varsayalım.
public Class myClass
{
public int prop1 {get;set;}
}
Şimdi bu prop1'e aşağıdaki gibi başka bir sınıfta erişiyorsunuz:
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref.prop1 = 1; //This line throws error
}
}
sınıfın myClass sınıfının başvurusu bildirilmiş ancak somutlaştırılmamış veya nesnenin bir örneği söz konusu sınıfın başvuru örneğine atanmamış olduğu için yukarıdaki satır hata veriyor.
Bunu düzeltmek için başlatmanız gerekir (bu sınıfın referansına nesne atayın).
public class Demo
{
public void testMethod()
{
myClass ref = null;
ref = new myClass();
ref.prop1 = 1;
}
}
Kullanmaya çalıştığınız sınıfın bir nesnesi örneklenmediğinde, bir nesnenin örneğine ayarlanmayan NullReferenceException veya Object başvurusu oluşur. Örneğin:
Öğrenci adında bir sınıfınız olduğunu varsayın.
public class Student
{
private string FirstName;
private string LastName;
public string GetFullName()
{
return FirstName + LastName;
}
}
Şimdi, öğrencinin tam adını almaya çalıştığınız başka bir sınıfı düşünün.
public class StudentInfo
{
public string GetStudentName()
{
Student s;
string fullname = s.GetFullName();
return fullname;
}
}
Yukarıdaki kodda görüldüğü gibi, Öğrenci s - ifadesi yalnızca Öğrenci türünün değişkenini bildirir, bu noktada Öğrenci sınıfının somutlaştırılmadığını unutmayın. Bu nedenle, s.GetFullName () ifadesi çalıştırıldığında, NullReferenceException özel durumunu atar.
Basit bir ifadeyle:
Oluşturulmamış veya şu anda bellekte olmayan bir nesneye erişmeye çalışıyorsunuz.
Peki bununla nasıl başa çıkılır:
Hata ayıklama ve hata ayıklayıcı kırmak ... Doğrudan sizi kırık değişkene götürecek ... Şimdi senin görevin bunu düzeltmek için .. Yeni anahtar kelimeyi uygun yerde kullanarak.
Nesne olmadığı için bazı veritabanı komutlarında kaynaklanıyorsa, tek yapmanız gereken boş bir denetim yapmak ve bunu işlemektir:
if (i == null) {
// Handle this
}
En zor olanı ... GC nesneyi zaten topladıysa ... Bu genellikle dizeleri kullanarak bir nesne bulmaya çalışıyorsanız gerçekleşir ... Yani, nesnenin adına göre bulmak, GC'nin zaten temizledim ... Bu bulmak zor ve oldukça sorun olacak ... Bu sorunu çözmenin daha iyi bir yolu, geliştirme sürecinde gerekli olan her yerde null kontroller yapmaktır. Bu size çok zaman kazandıracak.
İsimle bularak, bazı çerçeve dizeleri kullanarak FIndObjects izin sağlar ve kod şöyle görünebilir: FindObject ("ObjectName");
Kelimenin tam anlamıyla bir NullReferenceExeption düzeltmek için en kolay yolu iki yolu vardır. Örneğin bir betiği ve rb (rigidbody) adında bir değişkeni olan bir GameObject öğeniz varsa, bu değişken oyununuzu başlattığınızda null başlar.
Bu nedenle, bilgisayarda bu değişkente depolanmış veriler olmadığından bir NullReferenceExeption elde edersiniz.
Örnek olarak bir RigidBody değişkeni kullanacağım.
Verileri gerçekten kolayca birkaç şekilde ekleyebiliriz:
rb = GetComponent<Rigidbody>();
Start()
veya Awake()
fonksiyonlarınız altında en iyi şekilde çalışır . rb = AddComponent<RigidBody>();
Diğer Notlar: Birliğin nesnenize bir bileşen eklemesini istiyorsanız ve bir bileşen eklemeyi unutmuş olabilirseniz [RequireComponent(typeof(RigidBody))]
, sınıf bildiriminizin üzerine yazabilirsiniz (tüm kullanıcılarınızın altındaki boşluk).
Zevk ve eğlenceli oyunlar yapmak!
Bu kural dışı durumun atılabileceği yaygın senaryoları göz önünde bulundurursak, üstteki nesneye sahip özelliklere erişiriz.
Ör:
string postalcode=Customer.Address.PostalCode;
//if customer or address is null , this will through exeption
burada, adres null ise, NullReferenceException elde edersiniz.
Bu nedenle, bir uygulama olarak, bu tür nesnelerde (özellikle genel olarak) özelliklere erişmeden önce her zaman null check kullanmalıyız
string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Bu temelde bir Null referans istisnasıdır . As Microsoft devletlerde
Değeri null olan türdeki bir üyeye erişmeye çalıştığınızda bir NullReferenceException özel durumu atılır.
Bu, herhangi bir değeri olmayan herhangi bir üye varsa ve bu üyeyi belirli bir görevi yerine getirmesi için yaparsak, sistem şüphesiz bir mesaj atar ve
"Hey bekle, o üyenin değeri yok, bu yüzden teslim ettiğin görevi yerine getiremiyor."
İstisna, bir şeyin yönlendirildiğini ancak değerinin ayarlanmadığını söylüyor. Dolayısıyla, bu değer yalnızca referans türleri kullanılırken oluştuğuna işaret eder, çünkü Değer türleri geçersizdir.
Değer türü üyeler kullanırsak, NullReferenceException oluşmaz.
class Program
{
static void Main(string[] args)
{
string str = null;
Console.WriteLine(str.Length);
Console.ReadLine();
}
}
Yukarıdaki kod, boş bir değerle atanan basit dizeyi gösterir .
Şimdi, dize uzunluğunu yazdırmaya çalıştığımda str , ben alırım 'System.NullReferenceException' tür bir işlenmeyen istisna oluştu üyesi çünkü mesajı str boş işaret ettiği ve null herhangi bir uzunlukta olamaz.
' NullReferenceException ', başvuru türünü başlatmayı unuttuğumuzda da oluşur.
İçinde bir sınıf ve üye yöntemi olduğunu varsayalım. Sınıfımı başlattım, sadece sınıfımı adlandırdım. Şimdi yöntemi kullanmaya çalışırsam, derleyici bir hata atar veya bir uyarı verir (derleyiciye bağlı olarak).
class Program
{
static void Main(string[] args)
{
MyClass1 obj;
obj.foo(); //Use of unassigned local variable 'obj'
}
}
public class MyClass1
{
internal void foo()
{
Console.WriteLine("hello from foo");
}
}
Yukarıdaki kodun derleyicisi, değişken nesnesinin boş değerlere sahip olduğunu ya da hiçbir şeyin boşta olmadığını belirten obj nesnesinin atanmamış olduğuna dair bir hata oluşturur . Yukarıdaki kodun derleyicisi, değişken nesnesinin boş değerlere sahip olduğunu ya da hiçbir şeyin boşta olmadığını belirten obj nesnesinin atanmamış olduğuna dair bir hata oluşturur .
NullReferenceException, nesnenin değerini denetlemememiz nedeniyle ortaya çıkıyor. Kod geliştirmede genellikle nesne değerlerini işaretlemeden bırakırız.
Nesnelerimizi somutlaştırmayı unuttuğumuzda da ortaya çıkar. Boş değerleri döndürebilen veya ayarlayabilen yöntemler, özellikler, koleksiyonlar vb. Kullanmak da bu istisnanın nedeni olabilir.
Bu ünlü istisnayı önlemek için çeşitli yollar ve yöntemler vardır:
Açık Kontrol: Nesneleri, özellikleri, yöntemleri, dizileri ve koleksiyonları boş olup olmadıklarını kontrol etme geleneğine uymalıyız. Bu, if-else if-else vb. Gibi koşullu ifadeler kullanılarak basitçe uygulanabilir.
İstisna yönetimi: Bu istisnayı yönetmenin önemli yollarından biri. Basit try-catch-nihayet blokları kullanarak bu istisnayı kontrol edebilir ve bir günlüğünü tutabiliriz. Bu, uygulamanız üretim aşamasındayken çok yararlı olabilir.
Null işleçler: Null Coalescing operatörü ve null koşullu işleçler, nesnelere, değişkenlere, özelliklere ve alanlara değerler ayarlanırken de kullanışlı olarak kullanılabilir.
Hata ayıklayıcı: Geliştiriciler için büyük hata ayıklama silahımız var. Geliştirme yüzü sırasında NullReferenceException ile karşılaşırsak, istisnanın kaynağına ulaşmak için hata ayıklayıcıyı kullanabiliriz.
Yerleşik yöntem: GetValueOrDefault (), IsNullOrWhiteSpace () ve IsNullorEmpty () gibi sistem yöntemleri null olup olmadığını denetler ve null değeri varsa varsayılan değeri atar.
Burada zaten çok iyi cevaplar var. Blogumdaki örneklerle daha ayrıntılı açıklamayı da kontrol edebilirsiniz .
Umarım bu da yardımcı olur!
Derleme kaydedilirken veya derlenirken bu ileti görüntüleniyorsa, tüm dosyaları kapatın ve derlemek ve kaydetmek için herhangi bir dosyayı açın.
Benim için sebebi dosyayı yeniden adlandırmıştım ve eski dosya hala açıktı.