Co to jest wyjątek NullReferenceException i jak go naprawić?

1875

Mam trochę kodu, a kiedy się wykonuje, rzuca NullReferenceException, mówiąc:

Odwołanie do obiektu nie jest ustawione na instancję obiektu.

Co to znaczy i co mogę zrobić, aby naprawić ten błąd?

John Saunders
źródło
Pomocnik wyjątków w VS 2017 będzie bardziej pomocny w zdiagnozowaniu przyczyny tego wyjątku - blogs.msdn.microsoft.com/visualstudio/2016/11/28/… w ramach nowego pomocnika wyjątków .
Zev Spitz,
Drodzy przyszli goście, odpowiedzi na to pytanie dotyczą również wyjątku ArgumentNullException . Jeśli Twoje pytanie zostało zamknięte jako duplikat tego pytania i występuje ANE, postępuj zgodnie ze wskazówkami w odpowiedziach, aby debugować i rozwiązać problem.
@ ANE powinno się zdarzyć tylko wtedy, gdy jako parametr zostanie przekazany null Czy możesz podać przykład, jeśli pytanie ANE zostało zamknięte jako duplikat tego pytania?
John Saunders
Pojawił się na Meta, ale musiałbym poszukać linku. Ale jeśli chodzi o ten komentarz, ANE jest po prostu NRE, ale ktoś dodał kontrolę zapobiegawczą i przynajmniej wiesz dokładnie, co jest null (podana jest nazwa argumentu), więc łatwiej jest zdiagnozować niż zwykłe NRE.

Odpowiedzi:

2415

Jaka jest przyczyna?

Dolna linia

Próbujesz użyć czegoś, co jest null(lub Nothingw VB.NET). Oznacza to, że albo go ustawisznull , albo nigdy nie ustawisz go na niczym.

Jak wszystko inne, nullzostaje przekazany. Jeśli jest null w metodzie „A”, może to oznaczać, że metoda „B” przekazała metodę null do „A”.

null może mieć różne znaczenia:

    1. Zmienne obiektowe, które są niezainicjowane i dlatego nie wskazują na nic. W tym przypadku, jeśli dostęp do właściwości lub metody takich obiektów, to powoduje NullReferenceException.
    1. Deweloper używa nullcelowo, aby wskazać, że nie ma dostępnej znaczącej wartości. Zauważ, że C # ma pojęcie zerowalnych typów danych dla zmiennych (np. Tabele bazy danych mogą mieć pola zerowalne) - możesz przypisać nulldo nich, aby wskazać, że nie ma w nim żadnej wartości, na przykład int? a = null;tam, gdzie znak zapytania wskazuje, że może przechowywać null zmienna a. Możesz to sprawdzić za pomocą if (a.HasValue) {...}lub za pomocą if (a==null) {...}. Zmienne dopuszczające wartości zerowe, takie jak aten przykład, umożliwiają dostęp do wartości a.Valuejawnie lub tak samo normalnie przez a.
      Zauważ, że dostęp do niego przez a.Valuerzuca InvalidOperationExceptionzamiast zamiastNullReferenceException jeśli aIsnull- powinieneś zrobić to wcześniej, tzn. jeśli masz inną zmienną nullable int b;, powinieneś wykonywać zadania takie jak if (a.HasValue) { b = a.Value; }lub krótsze if (a != null) { b = a; }.

Pozostała część tego artykułu jest bardziej szczegółowa i pokazuje błędy, które często popełniają programiści, co może prowadzić do NullReferenceException .

Dokładniej

runtimeRzucanie NullReferenceException zawsze oznacza to samo: próbujesz użyć odwołania, a odniesienia nie jest zainicjowana (lub był raz zainicjowany, ale to już nie zainicjowany).

Oznacza to, że referencja jest nulli nie można uzyskać dostępu do członków (takich jak metody) poprzez nullreferencję. Najprostszy przypadek:

string foo = null;
foo.ToUpper();

Spowoduje to wyrzucenie a NullReferenceExceptionw drugiej linii, ponieważ nie można wywołać metody instancji ToUpper()dla stringodwołania wskazującego nanull .

Debugowanie

Jak znaleźć źródło NullReferenceException? Oprócz spojrzenia na sam wyjątek, który zostanie rzucony dokładnie w miejscu, w którym wystąpi, obowiązują ogólne zasady debugowania w Visual Studio: umieszczaj strategiczne punkty przerwania i sprawdzaj zmienne , najeżdżając myszką na ich nazwy, otwierając ( Szybko) Obserwuj okno lub korzystając z różnych paneli debugowania, takich jak Locals i Auto.

Jeśli chcesz dowiedzieć się, gdzie jest lub nie jest ustawione odniesienie, kliknij jego nazwę prawym przyciskiem myszy i wybierz „Znajdź wszystkie odniesienia”. Następnie możesz umieścić punkt przerwania w każdej znalezionej lokalizacji i uruchomić program z dołączonym debugerem. Za każdym razem, gdy debugger przełamie taki punkt przerwania, musisz ustalić, czy oczekujesz, że odwołanie ma wartość inną niż null, sprawdź zmienną i sprawdź, czy wskazuje ona instancję, kiedy tego oczekujesz.

Postępując zgodnie z przebiegiem programu w ten sposób, możesz znaleźć lokalizację, w której instancja nie powinna mieć wartości NULL, i dlaczego nie jest poprawnie ustawiona.

Przykłady

Niektóre typowe scenariusze, w których można zgłosić wyjątek:

Rodzajowy

ref1.ref2.ref3.member

Jeśli ref1 lub ref2 lub REF3 jest zerowy, to dostaniesz NullReferenceException. Jeśli chcesz rozwiązać problem, dowiedz się, który z nich jest pusty, przepisując wyrażenie na jego prostszy odpowiednik:

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

W szczególności, w HttpContext.Current.User.Identity.NameThe HttpContext.Currentmoże być zerowa lub Usernieruchomość może być null, lubIdentity nieruchomość może być zerowa.

Pośredni

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

Jeśli chcesz uniknąć odwołania zerowego podrzędnego (Osoba), możesz zainicjować je w konstruktorze obiektu nadrzędnego (Książka).

Inicjatory obiektów zagnieżdżonych

To samo dotyczy inicjalizatorów obiektów zagnieżdżonych:

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

To przekłada się na

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

Gdy newużywane jest słowo kluczowe, tworzy ono tylko nowe wystąpienie Book, ale nie nowe Person, więc Authorwłaściwość jest nadalnull .

Inicjatory kolekcji zagnieżdżonych

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

Kolekcja zagnieżdżona Initializerszachowuje się tak samo:

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

To przekłada się na

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

new PersonTylko tworzy instancję Person, ale Bookskolekcja jest nadal null. InitializerSkładnia kolekcji nie tworzy kolekcji p1.Books, tylko tłumaczy nap1.Books.Add(...) instrukcje.

Szyk

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

Elementy tablicy

Person[] people = new Person[5];
people[0].Age = 20 // people[0] is null. The array was allocated but not
                   // initialized. There is no Person to set the Age for.

Jagged Arrays

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.

Kolekcja / Lista / Słownik

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

Zakres zmiennej (pośredni / odroczony)

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.

Wydarzenia

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. 

klasa publiczna Form1 {klient prywatny;

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

}

Można to rozwiązać, postępując zgodnie z konwencją, aby poprzedzać pola znakiem podkreślenia:

    private Customer _customer;

Cykl życia strony ASP.NET:

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

Wartości sesji ASP.NET

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

Modele pustego widoku ASP.NET MVC

Jeśli wystąpi wyjątek podczas odwoływania się do właściwości @Modelw ASP.NET MVC View, musisz zrozumieć, że Modelmetoda ustawia się w metodzie akcji podczas returnprzeglądania. Po zwróceniu pustego modelu (lub właściwości modelu) z kontrolera wyjątek występuje, gdy widoki uzyskują do niego dostęp:

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

Kolejność tworzenia kontroli WPF i zdarzenia

WPFformanty są tworzone podczas połączenia InitializeComponentw kolejności, w jakiej pojawiają się w drzewie wizualnym. A NullReferenceExceptionzostanie podniesiony w przypadku wcześniej utworzonych elementów sterujących za pomocą procedur obsługi zdarzeń itp., InitializeComponentKtóre uruchamiają się, podczas których odwołują się elementy sterujące utworzone wcześniej.

Na przykład :

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

Tutaj comboBox1jest tworzony wcześniej label1. Jeśli comboBox1_SelectionChangedspróbujesz odwołać się do `label1, nie zostanie jeszcze utworzona.

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

Zmiana kolejności deklaracji w XAML(tj. Umieszczenie label1wcześniej comboBox1, ignorowanie kwestii filozofii projektowania, przynajmniej rozwiązałoby problemNullReferenceException tutaj.

Obsada z as

var myThing = someObject as Thing;

Nie rzuca to, InvalidCastExceptionale zwraca a, nullgdy rzutowanie się nie powiedzie (i gdy someObjectsam jest pusty). Więc bądź tego świadomy.

LINQ FirstOrDefault()iSingleOrDefault()

Proste wersje First()i Single()wyjątki, gdy nic nie ma. W takim przypadku wersje „OrDefault” zwracają wartość null. Więc bądź tego świadomy.

dla każdego

foreachrzuca, gdy próbujesz iterować pustą kolekcję. Zwykle spowodowane przez nieoczekiwany nullwynik metod zwracających kolekcje.

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

Bardziej realistyczny przykład - wybierz węzły z dokumentu XML. Wyrzuci, jeśli nie zostaną znalezione węzły, ale wstępne debugowanie pokazuje, że wszystkie właściwości są prawidłowe:

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

Sposoby, których należy unikać

Jawnie sprawdź nulli zignoruj ​​wartości puste.

Jeśli spodziewasz się, że odwołanie ma czasami wartość NULL, możesz sprawdzić, czy istnieje ono nullprzed uzyskaniem dostępu do członków instancji:

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

Jawnie sprawdź nulli podaj wartość domyślną.

Wywołane metody, które mają zostać zwrócone, mogą zwrócić instancję null, na przykład gdy szukany obiekt nie może zostać znaleziony. W takim przypadku możesz zwrócić wartość domyślną:

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

Jawnie sprawdź nullwywołania metod i wyślij niestandardowy wyjątek.

Możesz także rzucić niestandardowy wyjątek, aby złapać go w kodzie wywołującym:

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

Użyj, Debug.Assertjeśli wartość nigdy nie powinna byćnull , aby złapać problem wcześniej niż wystąpi wyjątek.

Jeśli podczas programowania wiesz, że metoda może, ale nigdy nie powinna powrócić null, możesz użyć jej, Debug.Assert()aby przerwać tak szybko, jak to możliwe, kiedy to nastąpi:

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

Chociaż to sprawdzenie nie zakończy się w kompilacji wydania , co spowoduje, że wyrzuci go NullReferenceExceptionponownie, gdy będzie book == nullw środowisku uruchomieniowym w trybie wydania.

Użyj GetValueOrDefault()dla nullabletypów wartości, aby podać wartość domyślną, gdy są 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

Użyj zerowego operatora koalescencyjnego: ??[C #] lub If()[VB].

Skrót do podania wartości domyślnej w przypadku nullnapotkania:

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

Użyj operatora warunku zerowego: ?.lub ?[x]dla tablic (dostępne w C # 6 i VB.NET 14):

Jest to również czasami nazywane operatorem bezpiecznej nawigacji lub Elvisa (po jego kształcie). Jeśli wyrażenie po lewej stronie operatora ma wartość NULL, to prawa strona nie będzie oceniana, a zamiast tego zwracana jest wartość NULL. Oznacza to, że takie przypadki:

var title = person.Title.ToUpper();

Jeśli dana osoba nie ma tytułu, spowoduje to zgłoszenie wyjątku, ponieważ próbuje ona wywołać ToUpperwłaściwość o wartości zerowej.

W C# 5i poniżej, może to być strzeżone z:

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

Teraz zmienna tytułowa będzie miała wartość NULL zamiast zgłaszać wyjątek. C # 6 wprowadza krótszą składnię do tego:

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

Spowoduje to powstanie zmiennej tytułowej null, a wywołanie do ToUppernie zostanie wykonane, jeśli tak person.Titlejest null.

Oczywiście nadal musisz sprawdzić titlewartość null lub użyć operatora warunku zerowego razem z operatorem koalescencji zerowej ( ??), aby podać wartość domyślną:

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

Podobnie, w przypadku tablic można używać ?[i]w następujący sposób:

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

Spowoduje to wykonanie następujących czynności: Jeśli myIntArrayjest null, wyrażenie zwraca null i można go bezpiecznie sprawdzić. Jeśli zawiera tablicę, zrobi to samo co: elem = myIntArray[i];i zwróci i<sup>th</sup>element.

Użyj kontekstu zerowego (dostępny w C # 8):

Wprowadzone C# 8tam typy zerowe i typy referencyjne zerowalne przeprowadzają analizę statyczną zmiennych i zapewniają ostrzeżenie kompilatora, jeśli wartość może być potencjalnie zerowa lub została ustawiona na null. Typy zerowalne pozwalają jawnie zezwolić, aby typy miały wartość null.

Kontekst adnotacji z dopuszczeniem wartości zerowej i kontekst ostrzeżenia o wartości dopuszczającej wartości zerowe można ustawić dla projektu za pomocą Nullableelementu z csprojpliku. Ten element konfiguruje sposób, w jaki kompilator interpretuje zerowanie typów oraz generowane ostrzeżenia. Prawidłowe ustawienia to:

  • enable: kontekst adnotacji zerowania jest włączony. Włączono kontekst ostrzegania o wartości zerowej. Zmienne typu odwołania, na przykład ciąg znaków, nie są zerowalne. Wszystkie ostrzeżenia o zerowaniu są włączone.
  • disable: kontekst adnotacji z dopuszczaniem wartości zerowych jest wyłączony. Kontekst ostrzeżenia o zerowaniu jest wyłączony. Zmienne typu referencyjnego są nieświadome, podobnie jak wcześniejsze wersje C #. Wszystkie ostrzeżenia o zerowaniu są wyłączone.
  • safeonly: włączono kontekst adnotacji z dopuszczaniem wartości zerowych. Niellable kontekst ostrzeżenia jest bezpieczny. Zmienne typu referencyjnego są niezerowalne. Wszystkie ostrzeżenia dotyczące zerowalności bezpieczeństwa są włączone.
  • ostrzeżenia: Kontekst dopuszczający wartości zerowe jest wyłączony. Włączono kontekst ostrzegania o wartości zerowej. Zmienne typu referencyjnego są nieświadome. Wszystkie ostrzeżenia o zerowaniu są włączone.
  • safeonlywarnings: kontekst adnotacji z dopuszczaniem wartości zerowych jest wyłączony. Niellable kontekst ostrzeżenia jest bezpieczny. Zmienne typu referencyjnego są nieświadome. Wszystkie ostrzeżenia dotyczące zerowalności bezpieczeństwa są włączone.

Typ odwołania zerowalnego jest odnotowywany przy użyciu tej samej składni, co typy wartości dopuszczających wartości zerowe: a ?jest dodawane do typu zmiennej.

Specjalne techniki debugowania i naprawy zerowych derefów w iteratorach

C#obsługuje „bloki iteratora” (zwane „generatorami” w niektórych innych popularnych językach). Wyjątki zerowania dereferencji mogą być szczególnie trudne do debugowania w blokach iteratora z powodu odroczonego wykonania:

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

Jeśli whateverwyniki w nullto MakeFrobrzuci. Teraz możesz pomyśleć, że właściwą rzeczą jest:

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

Dlaczego to źle? Ponieważ blok iteratora tak naprawdę nie działa aż do foreach! Wywołanie GetFrobspo prostu zwraca obiekt, który po iteracji uruchomi blok iteratora.

Pisząc czek zerowy w ten sposób, zapobiegasz zerowaniu, ale przenosisz wyjątek argumentu zerowego do punktu iteracji , a nie do punktu wywołania , a debugowanie jest bardzo mylące .

Prawidłowa poprawka to:

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

To znaczy, stwórz prywatną metodę pomocniczą, która ma logikę bloku iteratora, i publiczną metodę powierzchniową, która sprawdza zero i zwraca iterator. Teraz, gdy GetFrobsjest wywoływany, sprawdzanie wartości zerowej odbywa się natychmiast, a następnie GetFrobsForRealwykonuje się, gdy sekwencja jest iterowana.

Jeśli sprawdzisz źródło odniesienia LINQdo Obiektów, zobaczysz, że ta technika jest używana przez cały czas. Jest nieco bardziej niezręczny w pisaniu, ale znacznie ułatwia debugowanie błędów nieważności. Zoptymalizuj swój kod dla wygody dzwoniącego, a nie dla autora .

Uwaga na temat zerowych dereferencji w niebezpiecznym kodzie

C#ma tryb „niebezpieczny”, który, jak sama nazwa wskazuje, jest wyjątkowo niebezpieczny, ponieważ normalne mechanizmy bezpieczeństwa zapewniające bezpieczeństwo pamięci i bezpieczeństwo typu nie są egzekwowane. Nie powinieneś pisać niebezpiecznego kodu, chyba że dobrze rozumiesz, jak działa pamięć .

W trybie niebezpiecznym powinieneś wiedzieć o dwóch ważnych faktach:

  • dereferencing null pointer daje ten sam wyjątek jak dereferencing null odniesienia
  • usunięcie dereferencji z niepoprawnego wskaźnika o wartości innej niż zero może spowodować wyjątek w niektórych okolicznościach

Aby zrozumieć, dlaczego tak jest, pomaga zrozumieć, w jaki sposób .NET generuje wyjątki zerowania zerowania. (Te szczegóły dotyczą .NET działającego w systemie Windows; inne systemy operacyjne używają podobnych mechanizmów.)

Pamięć jest zwirtualizowana Windows; każdy proces otrzymuje wirtualną pamięć wielu „stron” pamięci, które są śledzone przez system operacyjny. Każda strona pamięci ma ustawione flagi, które określają, w jaki sposób można jej używać: czytać, zapisywać, wykonywać i tak dalej. Najniższa strona jest oznaczony jako „produkują błąd, jeśli kiedykolwiek używany w jakikolwiek sposób”.

Zarówno wskaźnik zerowy, jak i odwołanie zerowe w C#są wewnętrznie reprezentowane jako liczba zero, więc każda próba wyłuskiwania go w odpowiedniej pamięci powoduje, że system operacyjny powoduje błąd. Środowisko wykonawcze .NET wykrywa ten błąd i przekształca go w wyjątek zerowania.

Właśnie dlatego odsyłanie zarówno wskaźnika zerowego, jak i odwołania zerowego powoduje ten sam wyjątek.

A co z drugim punktem? Odwołanie do nieprawidłowego wskaźnika, który znajduje się na najniższej stronie pamięci wirtualnej, powoduje ten sam błąd systemu operacyjnego, a tym samym ten sam wyjątek.

Dlaczego to ma sens? Załóżmy, że mamy strukturę zawierającą dwie liczby całkowite i niezarządzany wskaźnik równy null. Jeśli spróbujemy wyrejestrować drugą liczbę CLRcałkowitą w strukturze, nie spróbuje ona uzyskać dostępu do pamięci w lokalizacji zero; uzyska dostęp do magazynu w czwartej lokalizacji. Ale logicznie jest to dereferencja zerowa, ponieważ docieramy do tego adresu za pomocą wartości zerowej.

Jeśli pracujesz z niebezpiecznym kodem i otrzymujesz wyjątek zerowania, po prostu pamiętaj, że obrażający wskaźnik nie musi mieć wartości zerowej. Może to być dowolna lokalizacja na najniższej stronie, a ten wyjątek zostanie wygenerowany.

LopDev
źródło
55
Może to głupi komentarz, ale czy pierwszym i najlepszym sposobem uniknięcia tego problemu byłoby zainicjowanie obiektu? Dla mnie ten błąd występuje zwykle dlatego, że zapomniałem zainicjować coś takiego jak element tablicy. Myślę, że o wiele rzadziej jest definiować obiekt jako zerowy, a następnie odwoływać się do niego. Być może podasz sposób rozwiązania każdego problemu związanego z opisem. Nadal dobry post.
JPK
30
Co jeśli nie ma obiektu, a raczej wartość zwracana z metody lub właściwości?
John Saunders
6
Przykład książki / autora jest trochę dziwny ... Jak to się w ogóle kompiluje? Jak w ogóle działa intellisense? Co to jest, nie jestem dobry z computar ...
5
@Will: czy moja ostatnia edycja pomaga? Jeśli nie, prosimy o wyraźniejsze określenie problemu.
John Saunders
6
@JohnSaunders O nie, przepraszam, miałem na myśli wersję tego obiektu inicjującego obiekt. new Book { Author = { Age = 45 } };Jak działa wewnętrzna inicjalizacja ... Nie mogę sobie wyobrazić sytuacji, w której wewnętrzna inicjacja kiedykolwiek działałaby, a jednak kompiluje się i działa intellisense ... Chyba że dla struktur?
311

Wyjątek NullReference - Visual Basic

NullReference ExceptionDla Visual Basic nie różni się od tej w języku C # . W końcu oboje zgłaszają ten sam wyjątek zdefiniowany w .NET Framework, którego oboje używają. Przyczyny unikalne dla Visual Basic są rzadkie (być może tylko jedna).

Ta odpowiedź będzie używać terminów, składni i kontekstu Visual Basic. Użyte przykłady pochodzą z wielu poprzednich pytań o przepełnienie stosu. To jest maksymalizacja trafności za pomocą rodzaju sytuacje często postrzegane w postach. Dla tych, którzy mogą go potrzebować, podano nieco więcej wyjaśnień. Przykładem podobne do Ciebie jest bardzo prawdopodobne tutaj wymienione.

Uwaga:

  1. Jest to oparte na koncepcji: nie ma kodu, który można wkleić do projektu. Ma on pomóc ci zrozumieć, co powodujeNullReferenceException (NRE), jak go znaleźć, jak go naprawić i jak go uniknąć. NRE może być wywołany na wiele sposobów, więc prawdopodobnie nie będzie to twoje jedyne spotkanie.
  2. Przykłady (z postów przepełnienia stosu) nie zawsze pokazują najlepszy sposób zrobienia czegoś w pierwszej kolejności.
  3. Zwykle stosuje się najprostsze lekarstwo.

Podstawowe znaczenie

Komunikat „Obiekt nie jest ustawiony na instancję obiektu” oznacza, że ​​próbujesz użyć obiektu, który nie został zainicjowany. Sprowadza się to do jednego z tych:

  • Kod zadeklarowana jest zmienna obiektu, ale nie zainicjować go (utworzyć wystąpienie lub " instancję ” it)
  • Coś, co zakładał twój kod, zainicjowałoby obiekt, ale nie
  • Być może inny kod przedwcześnie unieważnił obiekt nadal w użyciu

Znalezienie przyczyny

Ponieważ problemem jest odwołanie do obiektu, dlatego Nothingodpowiedzią jest ich zbadanie, aby dowiedzieć się, który z nich. Następnie określ, dlaczego nie został zainicjowany. Przytrzymaj wskaźnik myszy nad różnymi zmiennymi, a Visual Studio (VS) wyświetli ich wartości - sprawcą będzie Nothing.

Wyświetlanie debugowania IDE

Powinieneś także usunąć wszystkie bloki Try / Catch z odpowiedniego kodu, szczególnie te, w których nic nie ma w bloku Catch. Spowoduje to awarię kodu podczas próby użycia obiektu, który jest Nothing. To jest to, czego chcesz, ponieważ określi dokładną lokalizację problemu i pozwoli zidentyfikować obiekt, który go powoduje.

A MsgBoxin the Catch, który wyświetla, Error while...będzie mało pomocny. Ta metoda również prowadzi do bardzo złych pytań o przepełnienie stosu, ponieważ nie można opisać faktycznego wyjątku, zaangażowanego obiektu ani nawet wiersza kodu, w którym ma to miejsce.

Możesz także użyć Locals Window( Debuguj -> Windows -> Locals ), aby zbadać swoje obiekty.

Gdy wiesz, co i gdzie jest problem, zazwyczaj jest to dość łatwe do naprawienia i szybsze niż opublikowanie nowego pytania.

Zobacz też:

Przykłady i środki zaradcze

Obiekty klasy / Tworzenie instancji

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

Problem polega na tym, Dimże nie tworzy obiektu CashRegister ; deklaruje tylko zmienną regtego typu. Zadeklarowanie zmiennej obiektu i utworzenie instancji to dwie różne rzeczy.

Zaradzić

NewOperator często mogą być wykorzystywane do tworzenia instancji, gdy zadeklarujesz go:

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

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

Jeśli odpowiednie jest utworzenie instancji później:

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

Uwaga: Nie używaj Dimponownie w procedurze, łącznie z konstruktorem ( Sub New):

Private reg As CashRegister
'...

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

Spowoduje to utworzenie zmiennej lokalnejreg , która istnieje tylko w tym kontekście (pod). regZmiennej z poziomu modułu Scope, który będzie używany wszędzie indziej szczątki Nothing.

Brak Newoperatora jest przyczyną nr 1NullReference Exceptions sprawdzonych pytań o przepełnienie stosu.

Visual Basic próbuje wielokrotnie wyjaśniać proces za pomocą New: Użycie Newoperatora tworzy nowy obiekt i wywołuje Sub Newkonstruktor, w którym obiekt może wykonać dowolną inną inicjalizację.

Dla jasności Dim(lub Private) deklaruje tylko zmienną i jej zmienną Type. Zakres zmiennej - czy istnieje ona dla całego modułu / klasy lub jest lokalny procedurze - określa się , gdzie jest ona zadeklarowana. Private | Friend | Publicokreśla poziom dostępu, a nie zakres .

Aby uzyskać więcej informacji, zobacz:


Tablice

Tablice muszą być również tworzone:

Private arr as String()

Ta tablica została tylko zadeklarowana, a nie utworzona. Istnieje kilka sposobów inicjalizacji tablicy:

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

Uwaga: Począwszy od VS 2010, podczas inicjowania tablicy lokalnej za pomocą literału Option Infer, elementy As <Type>i Newsą opcjonalne:

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}

Typ danych i rozmiar tablicy są wywnioskowane z przypisywanych danych. Deklaracje poziomie modułu / klasa nadal wymagają As <Type>z Option Strict:

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

Przykład: tablica obiektów klasy

Dim arrFoo(5) As Foo

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

Tablica została utworzona, ale Fooobiektów w niej nie ma.

Zaradzić

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

Użycie a List(Of T)utrudni posiadanie elementu bez ważnego obiektu:

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

Aby uzyskać więcej informacji, zobacz:


Listy i kolekcje

Kolekcje .NET (których jest wiele odmian - Listy, Słownik itp.) Również muszą zostać utworzone lub utworzone.

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

Otrzymujesz ten sam wyjątek z tego samego powodu - myListzostał tylko zadeklarowany, ale nie utworzono żadnej instancji. Środek zaradczy jest taki sam:

myList = New List(Of String)

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

Częstym nadzorem jest klasa, która korzysta z kolekcji 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

Każda z procedur spowoduje NRE, ponieważ barListjest tylko deklarowana, a nie tworzona. Utworzenie wystąpienia Foonie spowoduje również utworzenia wystąpienia wewnętrznego barList. Być może zamierzano to zrobić w konstruktorze:

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

Tak jak poprzednio, jest to nieprawidłowe:

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

Aby uzyskać więcej informacji, zobacz List(Of T)Klasa .


Obiekty dostawcy danych

Praca z bazami danych stwarza wiele możliwości dla NullReference ponieważ może istnieć wiele obiektów ( Command, Connection, Transaction, Dataset, DataTable, DataRows....) w użytku od razu. Uwaga: Nie ma znaczenia, jakiego dostawcy danych używasz - MySQL, SQL Server, OleDB itp. - pojęcia są takie same.

Przykład 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

Tak jak poprzednio dsobiekt Dataset został zadeklarowany, ale instancja nigdy nie została utworzona. DataAdapterWypełni istniejącą DataSet, nie utworzyć. W tym przypadku, ponieważ dsjest to zmienna lokalna, IDE ostrzega, że może się to zdarzyć:

img

Po zadeklarowaniu jako zmienna na poziomie modułu / klasy, jak się wydaje con, kompilator nie może wiedzieć, czy obiekt został utworzony za pomocą procedury poprzedzającej. Nie ignoruj ​​ostrzeżeń.

Zaradzić

Dim ds As New DataSet

Przykład 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)

Literówka jest problemem tutaj: Employeesvs Employee. Nie DataTableutworzono nazwy „Pracownik”, więc NullReferenceExceptionwyniki próbują uzyskać do niej dostęp. Innym potencjalnym problemem jest założenie, że Itemsnie będzie, gdy SQL zawiera klauzulę WHERE.

Zaradzić

Ponieważ używa to jednej tabeli, użycie Tables(0)pozwoli uniknąć błędów ortograficznych. Badanie Rows.Countmoże również pomóc:

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

Filljest funkcją zwracającą liczbę Rowsdotkniętych, które można również przetestować:

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

Przykład 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

DataAdapterZapewni TableNamesjak pokazano w poprzednim przykładzie, ale nie nazwiska zanalizować z tabeli SQL lub bazy danych. W rezultacie,ds.Tables("TICKET_RESERVATION") odwołuje się do nieistniejącej tabeli.

Rozwiązanie jest takie samo, odwołać tabelę indeksu:

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

Zobacz także klasę DataTable .


Ścieżki do obiektu / zagnieżdżone

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

Kod testuje tylko Itemsoba elementy myFooi Barmoże być również niczym. Lekarstwem jest sprawdzenie całego łańcucha lub ścieżkę obiektów jednym na raz:

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

AndAlsojest ważne. Kolejne testy nie zostaną wykonane po Falsespełnieniu pierwszego warunku. Pozwala to kodowi bezpiecznie „wiercić” w obiekcie (ach) jeden „poziom” na raz, oceniając myFoo.Bardopiero po (i jeśli) myFooustaleniu, że jest poprawny. Łańcuchy obiektów lub ścieżki mogą być dość długie podczas kodowania złożonych obiektów:

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

Nie można odwoływać się do niczego „poniżej” nullobiektu. Dotyczy to również kontroli:

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

Tutaj, myWebBrowserlub Documentmoże być nic lub formfld1element nie może istnieć.


Kontrolki interfejsu użytkownika

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)

Między innymi ten kod nie przewiduje, że użytkownik mógł nie wybrać czegoś w co najmniej jednym elemencie sterującym interfejsu użytkownika. ListBox1.SelectedItemmoże być Nothing, więc ListBox1.SelectedItem.ToStringspowoduje NRE.

Zaradzić

Sprawdź poprawność danych przed ich użyciem (także Option Strictparametrami use i SQL):

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

Alternatywnie możesz użyć (ComboBox5.SelectedItem IsNot Nothing) AndAlso...


Formy Visual Basic

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

Jest to dość powszechny sposób na uzyskanie NRE. W języku C #, w zależności od sposobu kodowania, IDE zgłosi, że Controlsnie istnieje w bieżącym kontekście lub „nie może odwoływać się do elementu niestatycznego”. Tak więc do pewnego stopnia jest to sytuacja wyłącznie VB. Jest to również złożone, ponieważ może doprowadzić do kaskady awarii.

Tablice i kolekcje nie mogą być inicjowane w ten sposób. Ten kod inicjujący zostanie uruchomiony, zanim konstruktor utworzy znak Formlub Controls. W rezultacie:

  • Listy i kolekcja będą po prostu puste
  • Tablica będzie zawierać pięć elementów Nic
  • somevarPrzypisanie spowoduje natychmiastowego NRE bo nic nie posiada .Textwłasność

Odwołanie do elementów tablicy później spowoduje NRE. Jeśli zrobisz to z Form_Loadpowodu dziwnego błędu, IDE może nie zgłosić wyjątku, kiedy to się stanie. Wyjątek pojawi się później, gdy kod będzie próbował użyć tablicy. Ten „cichy wyjątek” został szczegółowo opisany w tym poście . Dla naszych celów kluczem jest to, że gdy dzieje się coś katastrofalnego podczas tworzenia formularza ( Sub Newlub Form Loadzdarzenia), wyjątki mogą nie zostać zgłoszone, kod kończy procedurę i wyświetla tylko formularz.

Ponieważ żaden inny kod w Twoim Sub Newlub Form Loadzdarzeniu nie będzie działał po NRE, wiele innych rzeczy może pozostać niezainicjowanych.

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

Uwaga: dotyczy to wszystkich odniesień do kontroli i komponentów, które czynią je nielegalnymi, gdy są:

Public Class Form1

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

Częściowe rozwiązanie

To ciekawe, że VB nie daje ostrzeżenie, ale rozwiązaniem jest zadeklarować pojemniki na poziomie formy, ale zainicjować ich obsługi zdarzeń obciążenia forma gdy kontrole zrobić istnieć. Można to zrobić, Sub Newdopóki kod jest po InitializeComponentwywołaniu:

' 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

Kod tablicy może jeszcze nie wyjść z lasu. Wszelkie formanty znajdujące się w kontrolce kontenera (jak a GroupBoxlub Panel) nie zostaną znalezione w Me.Controls; będą znajdować się w kolekcji Controls tego panelu lub GroupBox. Formant nie zostanie również zwrócony, gdy nazwa formantu zostanie źle napisana ( "TeStBox2"). W takich przypadkach Nothingponownie zostaną zapisane w tych elementach tablicy, a podczas próby odniesienia do nich powstanie NRE.

Powinny być łatwe do znalezienia teraz, gdy wiesz, czego szukasz: VS pokazuje błąd twoich działań

„Button2” znajduje się na Panel

Zaradzić

Zamiast pośrednich odniesień według nazwy przy użyciu Controlskolekcji formularza , użyj odwołania kontrolnego:

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

Funkcja nic nie zwraca

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

Jest to przypadek, w którym IDE ostrzega, że ​​„ nie wszystkie ścieżki zwracają wartość i NullReferenceExceptionmoże wynikać ”. Możesz wyłączyć ostrzeżenie, zastępując Exit Functionje Return Nothing, ale to nie rozwiązuje problemu. Wszystko, co próbuje użyć return, kiedy someCondition = Falsespowoduje NRE:

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

Zaradzić

Zamień Exit Functionw funkcji na Return bList. Zwracanie pustego List nie jest tym samym, co zwracanie Nothing. Jeśli istnieje szansa, że ​​zwrócony obiekt może być Nothing, przetestuj go przed użyciem:

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

Źle zaimplementowane Try / Catch

Źle zaimplementowana funkcja Try / Catch może ukryć problem i doprowadzić do powstania nowych:

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

Jest to przypadek, w którym obiekt nie jest tworzony zgodnie z oczekiwaniami, ale pokazuje także przydatność licznika pustego Catch.

W kodzie SQL występuje dodatkowy przecinek (po „adresie mailowym”), co powoduje wyjątek o nazwie .ExecuteReader. Po tym, Catchjak nic nie robi, Finallypróbuje wykonać czyszczenie, ale ponieważ nie można Closewyzerować DataReaderobiektu, wyniki są zupełnie nowe NullReferenceException.

Pusty Catchblok to diabelski plac zabaw. Ten PO był zaskoczony, dlaczego dostaje NRE w Finallybloku. W innych sytuacjach pusta Catchmoże skutkować czymś znacznie dalej idącym do szaleństwa i powodować, że spędzasz czas na szukaniu niewłaściwych rzeczy w niewłaściwym miejscu dla problemu. („Cichy wyjątek” opisany powyżej zapewnia tę samą wartość rozrywkową).

Zaradzić

Nie używaj pustych bloków Try / Catch - pozwól na awarię kodu, abyś mógł a) zidentyfikować przyczynę b) zidentyfikować lokalizację ic) zastosować odpowiednie rozwiązanie. Bloki Try / Catch nie mają na celu ukrycia wyjątków od osoby wyjątkowo wykwalifikowanej do ich naprawy - programisty.


DBNull to nie to samo, co Nic

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

IsDBNullFunkcja służy do sprawdzania, czy dana wartość jest równa System.DBNull: Od MSDN:

Wartość System.DBNull wskazuje, że Obiekt reprezentuje brakujące lub nieistniejące dane. DBNull to nie to samo co Nic, co wskazuje, że zmienna nie została jeszcze zainicjowana.

Zaradzić

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

Tak jak poprzednio, możesz przetestować na Nic, a następnie na określoną wartość:

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

Przykład 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
       ...

FirstOrDefaultzwraca pierwszy element lub wartość domyślną, która dotyczy Nothingtypów referencyjnych i nigdy DBNull:

If getFoo IsNot Nothing Then...

Sterownica

Dim chk As CheckBox

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

Jeżeli CheckBoxze chkNamenie można znaleźć (lub istnieje w GroupBox), wówczas chkbędzie nic i być próbuje odwołać każdą własność spowoduje wyjątek.

Zaradzić

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

DataGridView

DGV ma okresowo kilka dziwactw:

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"

Jeśli dgvBookstak AutoGenerateColumns = True, utworzy kolumny, ale ich nie nazwie, więc powyższy kod zawodzi, gdy odwołuje się do nich po nazwie.

Zaradzić

Nazwij kolumny ręcznie lub odwołaj się do nich według indeksu:

dgvBooks.Columns(0).Visible = True

Przykład 2 - Strzeż się NewRow

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

Gdy twój DataGridViewma AllowUserToAddRowsjako True(domyślny), wszystkie Cellsw pustym / nowym wierszu na dole będą zawierać Nothing. Większość prób użycia zawartości (na przykład ToString) spowoduje NRE.

Zaradzić

Użyj For/Eachpętli i przetestuj IsNewRowwłaściwość, aby ustalić, czy jest to ostatni wiersz. Działa AllowUserToAddRowsto niezależnie od tego, czy jest prawdziwe:

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

Jeśli używasz For npętli, zmień liczbę wierszy lub użyj, Exit Forgdy IsNewRowjest to prawda.


My.Settings (StringCollection)

W pewnych okolicznościach próba użycia elementu, z My.Settingsktórego jest, StringCollectionmoże spowodować NullReference przy pierwszym użyciu. Rozwiązanie jest takie samo, ale nie tak oczywiste. Rozważać:

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

Ponieważ VB zarządza Twoimi ustawieniami, uzasadnione jest oczekiwanie, że zainicjuje on kolekcję. Będzie, ale tylko wtedy, gdy wcześniej dodałeś początkowy wpis do kolekcji (w edytorze ustawień). Ponieważ kolekcja jest (najwidoczniej) inicjowana podczas dodawania elementu, pozostaje, Nothinggdy nie ma żadnych elementów w edytorze ustawień do dodania.

Zaradzić

Zainicjuj kolekcję ustawień w Loadmodule obsługi zdarzeń formularza , jeśli / w razie potrzeby:

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

Zazwyczaj Settingskolekcję należy zainicjować tylko przy pierwszym uruchomieniu aplikacji. Alternatywnym rozwiązaniem jest dodanie początkowej wartości do kolekcji w Projekcie -> Ustawienia | FooBars , zapisz projekt, a następnie usuń fałszywą wartość.


Kluczowe punkty

Prawdopodobnie zapomniałeś Newoperatora.

lub

Coś, co zakładałeś, że działałoby bezbłędnie, aby zwrócić zainicjowany obiekt do twojego kodu, nie zrobiło tego.

Nie ignoruj ​​ostrzeżeń kompilatora (zawsze) i używaj Option Strict On(zawsze).


MSDN NullReference Exception

Plutonix
źródło
226

Innym scenariuszem jest rzutowanie pustego obiektu na typ wartości . Na przykład poniższy kod:

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

Rzuci a NullReferenceExceptionna obsadę. Wydaje się to dość oczywiste w powyższej próbce, ale może się to zdarzyć w bardziej skomplikowanych scenariuszach z „późnym wiązaniem”, w których obiekt zerowy został zwrócony z kodu, którego nie posiadasz, a rzutowanie jest na przykład generowane przez jakiś automatyczny system.

Jednym z przykładów jest ten prosty fragment wiązania ASP.NET z kontrolką Kalendarz:

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

Tutaj, SelectedDatew rzeczywistości jest nieruchomość - od DateTimetypu - o Calendarkontroli typu Web, a wiązanie mogłaby doskonale powrócić coś null. Domniemany generator ASP.NET utworzy fragment kodu, który będzie równoważny powyższemu rzutowanemu kodowi. A to podniesieNullReferenceException dość trudny do wykrycia, ponieważ leży w kodzie wygenerowanym przez ASP.NET, który dobrze się kompiluje ...

Simon Mourier
źródło
7
Ładny chwyt. Jednoliniowy sposób na uniknięcie:DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Serge Shultz
159

Oznacza to, że dana zmienna nie jest wskazywana na nic. Mógłbym to wygenerować tak:

SqlConnection connection = null;
connection.Open();

Spowoduje to błąd, ponieważ podczas gdy zadeklarowałem zmienną „connection ”, nie jest na nic wskazywana. Kiedy próbuję zadzwonić do członka „ Open”, nie ma odniesienia do rozwiązania, a błąd zostanie zgłoszony.

Aby uniknąć tego błędu:

  1. Zawsze inicjuj swoje obiekty, zanim spróbujesz cokolwiek z nimi zrobić.
  2. Jeśli nie masz pewności, czy obiekt jest pusty, sprawdź to za pomocą object == null.

Narzędzie Resharper JetBrains zidentyfikuje każde miejsce w kodzie, w którym istnieje możliwość wystąpienia błędu zerowego odniesienia, umożliwiając sprawdzenie wartości zerowej. Ten błąd jest głównym źródłem błędów, IMHO.

Chris B. Behrens
źródło
3
Narzędzie Resharper JetBrains zidentyfikuje każde miejsce w kodzie, w którym istnieje możliwość wystąpienia błędu zerowego odniesienia. To jest niepoprawne. Mam rozwiązanie bez tego wykrywania, ale kod czasami powoduje wyjątek. Podejrzewam, że czasami jest to niewykrywalne - przynajmniej przez nich - w przypadku wielowątkowości, ale nie mogę komentować dalej, ponieważ nie zidentyfikowałem jeszcze lokalizacji mojego błędu.
j Riv
Ale jak go rozwiązać, gdy pojawi się wyjątek NullReferenceException w usign HttpContext.Current.Responce.Clear (). Nie rozwiązuje go żadne z powyższych rozwiązań. ponieważ podczas tworzenia obiektu obiektu HttpContext pojawia się błąd „Rozwiązanie problemu z przeciążeniem nie powiodło się, ponieważ żadne dostępne„ Nowe ”nie akceptuje tej liczby argumentów.
Sunny Sandeep
157

Oznacza to, że Twój kod używał zmiennej odwołania do obiektu, która została ustawiona na null (tzn. Nie odwoływała się do rzeczywistej instancji obiektu).

Aby uniknąć błędu, przed użyciem należy przetestować obiekty, które mogą mieć wartość NULL.

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
}
Jonathan Wood
źródło
96

Należy pamiętać, że niezależnie od scenariusza przyczyna jest zawsze taka sama w .NET:

Próbujesz użyć zmiennej referencyjnej, której wartością jest Nothing/ null. Gdy wartością jest Nothing/ nulldla zmiennej referencyjnej, oznacza to, że tak naprawdę nie przechowuje ona referencji do instancji dowolnego obiektu istniejącego na stercie.

Albo nigdy nie przypisałeś czegoś do zmiennej, nigdy nie utworzyłeś instancji wartości przypisanej do zmiennej, lub ustawiłeś zmienną na wartość Nothing/ nullręcznie, lub wywołałeś funkcję, która ustawiła zmienną na Nothing/ nulldla ciebie.

mistrz kodu
źródło
87

Przykład zgłaszanego wyjątku to: Gdy próbujesz coś sprawdzić, jest to zerowe.

Na przykład:

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
} 

Środowisko wykonawcze .NET zgłosi wyjątek NullReferenceException, gdy spróbujesz wykonać akcję na czymś, co nie zostało utworzone, np. Powyższy kod.

W porównaniu z ArgumentNullException, który jest zwykle rzucany jako środek obronny, jeśli metoda oczekuje, że to, co jest przekazywane, nie jest zerowe.

Więcej informacji znajduje się w C # NullReferenceException i Null Parameter .

Alex KeySmith
źródło
87

Aktualizacja C # 8.0, 2019: typy odniesienia zerowalne

C # 8.0 wprowadza typy odwołania zerowalne i typy zerowalne . Dlatego należy sprawdzić tylko typy zerowalne, aby uniknąć wyjątku NullReferenceException .


Jeśli nie zainicjowałeś typu odwołania i chcesz ustawić lub odczytać jedną z jego właściwości, wygeneruje wyjątek NullReferenceException .

Przykład:

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

Można tego po prostu uniknąć, sprawdzając, czy zmienna nie ma wartości null:

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

Aby w pełni zrozumieć, dlaczego zgłaszany jest wyjątek NullReferenceException, ważne jest, aby znać różnicę między nimi typami wartości a [typami referencyjnymi] [3].

Więc jeśli masz do czynienia z typami wartości , NullReferenceExceptions może nie wystąpić. Chociaż musisz zachować czujność, gdy masz do czynienia typami referencyjnymi !

Tylko typy referencyjne, jak sama nazwa wskazuje, mogą zawierać referencje lub dosłownie wskazywać na nic (lub „null”). Podczas gdy typy wartości zawsze zawierają wartość.

Typy referencyjne (te należy sprawdzić):

  • dynamiczny
  • obiekt
  • strunowy

Typy wartości (możesz po prostu zignorować te):

  • Typy numeryczne
  • Typy całkowe
  • Typy zmiennoprzecinkowe
  • dziesiętny
  • bool
  • Struktury zdefiniowane przez użytkownika
Fabian Bigler
źródło
6
-1: ponieważ pytanie brzmi „Co to jest NullReferenceException”, typy wartości nie są istotne.
John Saunders
21
@John Saunders: Nie zgadzam się. Jako twórca oprogramowania bardzo ważne jest, aby móc rozróżniać typy wartości i typy referencyjne. inaczej ludzie skończą sprawdzając, czy liczby całkowite są zerowe.
Fabian Bigler
5
To prawda, po prostu nie w kontekście tego pytania.
John Saunders
4
Dzięki za podpowiedź. Trochę go poprawiłem i dodałem przykład na górze. Nadal uważam, że warto wymienić odniesienia i typy wartości.
Fabian Bigler
5
Myślę, że nie dodałeś niczego, co nie było w innych odpowiedziach, ponieważ pytanie zakłada typ odniesienia.
John Saunders
78

Innym przypadkiem, w którym NullReferenceExceptionsmoże się zdarzyć, jest (nieprawidłowe) użycie asoperatora :

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

W tym przypadku, Booki Carto niezgodne rodzajów; Carnie można przekształcić / rzutowany na Book. Gdy rzutowanie nie powiedzie się, aspowraca null. Używanie mybookpóźniej powodujeNullReferenceException .

Ogólnie rzecz biorąc, powinieneś użyć obsady lub as:

Jeśli oczekujesz, że konwersja typu zawsze się powiedzie (tzn. Wiesz, co obiekt powinien wyprzedzić), powinieneś użyć rzutowania:

ComicBook cb = (ComicBook)specificBook;

Jeśli nie masz pewności co do typu, ale chcesz spróbować użyć go jako określonego typu, użyj as:

ComicBook cb = specificBook as ComicBook;
if (cb != null) {
   // ...
}
Jonathon Reinhart
źródło
2
Może się to zdarzyć często podczas rozpakowywania zmiennej. Często zdarza się to w procedurach obsługi zdarzeń po zmianie typu elementu interfejsu użytkownika, ale zapominam o aktualizacji kodu.
Brendan
65

Używasz obiektu zawierającego odwołanie do wartości zerowej. Daje to zerowy wyjątek. W tym przykładzie wartość ciągu jest pusta i podczas sprawdzania jego długości wystąpił wyjątek.

Przykład:

string value = null;
if (value.Length == 0) // <-- Causes exception
{
    Console.WriteLine(value); // <-- Never reached
}

Błąd wyjątku to:

Nieobsługiwany wyjątek:

System.NullReferenceException: Odwołanie do obiektu nie jest ustawione na instancję obiektu. w Program.Main ()

użytkownik1814380
źródło
1
Jak głęboka! Nigdy nie uważałem stałej „zerowej” za wartość odniesienia. Więc w ten sposób C # wyodrębnia „NullPointer”, co? B / c, jak pamiętam w C ++, NPE może być spowodowany dereferencją niezainicjowanego wskaźnika (tj. Wpisz ref w c #), którego wartością domyślną jest adres, który nie jest przypisany do tego procesu (w wielu przypadkach byłoby to 0, szczególnie w późniejszych wersjach C ++, które wykonały automatyczną inicjalizację, która należy do systemu operacyjnego - f wraz z nim i umrzeć w dół (lub po prostu złapać sigkill, za pomocą którego system atakuje twój proces).
samis
64

Podczas gdy to, co powoduje NullReferenceExceptions i podejścia do unikania / naprawiania takiego wyjątku, zostały omówione w innych odpowiedziach, wielu programistów jeszcze się nie nauczyło, jak samodzielnie debugować takie wyjątki podczas programowania.

W Visual Studio jest to zwykle łatwe dzięki Visual Studio Debugger .


Po pierwsze, upewnij się, że wychwycony zostanie prawidłowy błąd - patrz Jak zezwolić na zerwanie w „System.NullReferenceException” w VS2010? Uwaga 1

Następnie rozpocznij od debugowania (F5) lub dołącz [debugger VS] do uruchomionego procesu . Czasami może być użytecznyDebugger.Break , które wyświetli monit o uruchomienie debuggera.

Teraz, gdy zostanie zgłoszony (lub nieobsługiwany) wyjątek NullReferenceException, debugger zatrzyma się (pamiętasz powyższą regułę?) W linii, w której wystąpił wyjątek. Czasami błąd będzie łatwy do wykrycia.

Na przykład w poniższym wierszu jedynym kodem, który może spowodować wyjątek, jest myStringwartość zero. Można to zweryfikować, patrząc na okno obserwacyjne lub uruchamiając wyrażenia w oknie natychmiastowym .

var x = myString.Trim();

W bardziej zaawansowanych przypadkach, takich jak poniższe, musisz użyć jednej z powyższych technik (Obejrzyj lub Natychmiastowy system Windows), aby sprawdzić wyrażenia w celu ustalenia, czy jest str1to null, czy jeśli str2było null.

var x = str1.Trim() + str2.Trim();

Raz gdzie wyjątek jest rzut został zlokalizowany, to zazwyczaj banalne do rozumu do tyłu, aby dowiedzieć się, gdzie wartość NULL [nieprawidłowo] wprowadzono -

Poświęć czas na zrozumienie przyczyny wyjątku. Sprawdź wyrażenia zerowe. Sprawdź poprzednie wyrażenia, które mogły spowodować takie wyrażenia zerowe. Dodaj punkty przerwania i wykonaj odpowiednie kroki programu. Użyj debugera.


1 Jeśli Break on Throws jest zbyt agresywny, a debugger zatrzymuje się na NPE w bibliotece .NET lub w bibliotece innej firmy, Break on Unhandled może być wykorzystany do ograniczenia przechwyconych wyjątków. Dodatkowo VS2012 wprowadza Just My Code, który polecam również włączyć .

W przypadku debugowania z włączoną funkcją Just My Code zachowanie jest nieco inne. Po włączeniu Just My Code debugger ignoruje wyjątki środowiska uruchomieniowego CLR pierwszej klasy, które są wyrzucane poza Mój kod i nie przechodzą przez Mój kod

2864740
źródło
59

Simon Mourier podał ten przykład :

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

gdzie unboxing konwersji (cast) z object (lub z jednej z klas System.ValueTypelub System.Enumczy od typu interfejsu) do typu wartości (inne niż Nullable<>) sam w sobie dajeNullReferenceException .

W drugim kierunku, boks konwersji zNullable<> , który ma HasValuerówny false z typu odniesienia, można podać nullodniesienie, który później może prowadzić do NullReferenceException. Klasyczny przykład to:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

Czasami boks dzieje się w inny sposób. Na przykład za pomocą tej niestandardowej metody rozszerzenia:

public static void MyExtension(this object x)
{
  x.ToString();
}

następujący kod będzie problematyczny:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Te przypadki powstają z powodu specjalnych zasad, które środowisko wykonawcze stosuje podczas tworzenia boksu Nullable<>.

Jeppe Stig Nielsen
źródło
42

Dodanie przypadku, gdy nazwa klasy dla encji użytej w strukturze encji jest taka sama jak nazwa klasy dla pliku internetowego z kodem.

Załóżmy, że masz formularz internetowy Contact.aspx, którego klasą kodebehind jest Kontakt i masz nazwę encji Kontakt.

Następnie następujący kod zgłosi wyjątek NullReferenceException podczas wywoływania kontekstu.SaveChanges ()

Contact contact = new Contact { Name = "Abhinav"};
var context = new DataContext();
context.Contacts.Add(contact);
context.SaveChanges(); // NullReferenceException at this line

Ze względu na kompletność klasy DataContext

public class DataContext : DbContext 
{
    public DbSet<Contact> Contacts {get; set;}
}

i klasa jednostki kontaktowej. Czasami klasy jednostek są częściowymi klasami, dzięki czemu można je również rozszerzyć na inne pliki.

public partial class Contact 
{
    public string Name {get; set;}
}

Błąd występuje, gdy zarówno encja, jak i klasa codebehind znajdują się w tej samej przestrzeni nazw. Aby to naprawić, zmień nazwę klasy encji lub klasy codebehind na Contact.aspx.

Powód Nadal nie jestem pewien przyczyny. Ale ilekroć dowolna klasa jednostek rozszerzy System.Web.UI.Page, ten błąd występuje.

Do dyskusji spójrz na NullReferenceException w DbContext.saveChanges ()

AbhinavRanjan
źródło
41

Innym ogólnym przypadkiem, w którym można otrzymać ten wyjątek, są drwiny z klas podczas testów jednostkowych. Bez względu na stosowane ramy próbne należy upewnić się, że wszystkie odpowiednie poziomy hierarchii klas są odpowiednio wyśmiewane. W szczególności wszystkie właściwości, do HttpContextktórych odwołuje się testowany kod, muszą zostać wyszydzone.

Zobacz „ NullReferenceException zgłaszany podczas testowania niestandardowego atrybutu AuthorizationAttribute ”, aby uzyskać nieco pełny przykład.

John Saunders
źródło
40

Mam inne spojrzenie na odpowiedź na to pytanie. Tego rodzaju odpowiedzi „co jeszcze mogę zrobić, aby tego uniknąć?

Podczas pracy na różnych warstwach , na przykład w aplikacji MVC, kontroler potrzebuje usług do wywoływania operacji biznesowych. W takich scenariuszach można użyć kontenera wstrzykiwania zależności do zainicjowania usług, aby uniknąć wyjątku NullReferenceException . Oznacza to, że nie musisz się martwić sprawdzaniem wartości zerowej i po prostu wywołujesz usługi z kontrolera, tak jakby zawsze były dostępne (i inicjowane) jako singleton lub prototyp.

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();
    }
}
Mukus
źródło
6
-1: obsługuje tylko jeden scenariusz - niezainicjowane zależności. To jest scenariusz mniejszości dla NullReferenceException. Większość przypadków to zwykłe nieporozumienie dotyczące działania obiektów. Następne najczęściej występują inne sytuacje, w których deweloper założył, że obiekt zostanie zainicjowany automatycznie.
John Saunders
Wstrzykiwanie zależności nie jest zwykle stosowane w celu uniknięcia wyjątku NullReferenceException. Nie wierzę, że znalazłeś tutaj ogólny scenariusz. W każdym razie, jeśli edytujesz swoją odpowiedź, aby była bardziej w stylu stackoverflow.com/a/15232518/76337 , usunę głosowanie negatywne.
John Saunders,
38

W kwestii „co mam z tym zrobić” może być wiele odpowiedzi.

Bardziej „formalnym” sposobem zapobiegania takim błędom podczas opracowywania jest stosowanie projektu w umowie w kodzie. Oznacza to, że trzeba ustawić klasy niezmienników i / lub nawet funkcja / metoda warunki i postconditions na komputerze, podczas gdy rozwija.

Krótko mówiąc, niezmienniki klasowe zapewniają, że będą pewne ograniczenia w klasie, które nie zostaną naruszone podczas normalnego użytkowania (a zatem klasa nie przejdzie w niespójny stan). Warunki oznaczają, że dane podane jako wejście do funkcji / metody musi podążać ustawić pewne ograniczenia i nigdy ich naruszać, a postconditions oznacza, że wyjście funkcja / metoda musi przestrzegać ustalonych ograniczeń ponownie bez kiedykolwiek ich naruszenie. Warunki umowy nie powinny być nigdy naruszane podczas wykonywania programu wolnego od błędów, dlatego projektowanie według umowy jest sprawdzane w praktyce w trybie debugowania, podczas gdy jest wyłączone w wydaniach , aby zmaksymalizować wydajność opracowanego systemu.

W ten sposób można uniknąć NullReferenceExceptionprzypadków, które są wynikiem naruszenia zestawu ograniczeń. Na przykład, jeśli użyjesz właściwości obiektu Xw klasie, a później spróbujesz wywołać jedną z jej metod i Xma ona wartość zerową, spowoduje to NullReferenceException:

public X { get; set; }

public void InvokeX()
{
    X.DoSomething(); // if X value is null, you will get a NullReferenceException
}

Jeśli jednak ustawisz „właściwość X nigdy nie może mieć wartości zerowej” jako warunek wstępny metody, możesz zapobiec scenariuszowi opisanemu wcześniej:

//Using code contracts:
[ContractInvariantMethod]
protected void ObjectInvariant () 
{
    Contract.Invariant ( X != null );
    //...
}

Z tego powodu istnieje projekt Code Contracts dla aplikacji .NET.

Alternatywnie, projekt na podstawie umowy może być zastosowany przy użyciu asercji .

AKTUALIZACJA: Warto wspomnieć, że termin został ukuty przez Bertranda Meyera w związku z jego projektem języka programowania Eiffel .

Nick L.
źródło
2
Pomyślałem o dodaniu tego, ponieważ nikt o tym nie wspominał, a jeśli chodzi o podejście, moim zamiarem było wzbogacenie tematu.
Nick Louloudakis,
2
Dziękujemy za wzbogacenie tematu. Podałem opinię o twoim dodatku. Teraz inni mogą zrobić to samo.
John Saunders,
2
Pomyślałem, że jest to cenny dodatek do tematu, biorąc pod uwagę, że jest to bardzo popularny wątek. Słyszałem wcześniej o kodeksach i było to dobre przypomnienie, aby rozważyć ich użycie.
VoteCoffee
36

A NullReferenceExceptionjest wyrzucany, gdy próbujemy uzyskać dostęp do właściwości obiektu zerowego lub gdy wartość ciągu staje się pusta i próbujemy uzyskać dostęp do metod ciągu.

Na przykład:

  1. Gdy uzyskano dostęp do metody ciągu pustego:

    string str = string.Empty;
    str.ToLower(); // throw null reference exception
  2. Gdy uzyskano dostęp do właściwości pustego obiektu:

    Public Class Person {
        public string Name { get; set; }
    }
    Person objPerson;
    objPerson.Name  /// throw Null refernce Exception 
Hemant Bavle
źródło
2
To jest niepoprawne. String.Empty.ToLower()nie zgłosi wyjątku zerowego odniesienia. Reprezentuje rzeczywisty ciąg, choć pusty (tj "".). Ponieważ ma to obiekt do wywołania ToLower(), nie ma sensu umieszczać w nim wyjątku o wartości zerowej.
Kjartan
31

TL; DR: Spróbuj użyć Html.PartialzamiastRenderpage


Otrzymywałem, Object reference not set to an instance of an objectgdy próbowałem renderować widok w widoku, wysyłając mu model, taki jak ten:

@{
    MyEntity M = new MyEntity();
}
@RenderPage("_MyOtherView.cshtml", M); // error in _MyOtherView, the Model was Null

Debugowanie pokazało, że model był pusty w MyOtherView. Aż zmieniłem to na:

@{
    MyEntity M = new MyEntity();
}
@Html.Partial("_MyOtherView.cshtml", M);

I zadziałało.

Ponadto powodem, dla którego nie musiałem Html.Partialzaczynać, było to, że Visual Studio czasami rzuca wyglądające na błędne linie, pod którymi Html.Partialznajduje się w inaczej skonstruowanej foreachpętli, mimo że tak naprawdę nie jest to błąd:

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

Ale udało mi się uruchomić aplikację bez problemów z tym „błędem”. Mogłem pozbyć się błędu, zmieniając strukturę foreachpętli, aby wyglądała następująco:

@foreach(var M in MyEntities){
    ...
}

Chociaż mam wrażenie, że było tak, ponieważ Visual Studio źle odczytał znaki handlowe i nawiasy klamrowe.

Travis Heeter
źródło
Chciałeś Html.Partial, nie@Html.Partial
John Saunders
Pokaż także, która linia zwróciła wyjątek i dlaczego.
John Saunders
Wystąpił błąd w MyOtherView.cshtml, którego tutaj nie uwzględniłem, ponieważ model nie został poprawnie wysłany (tak było Null), więc wiedziałem, że błąd dotyczy sposobu wysyłania modelu.
Travis Heeter
22

Co możesz z tym zrobić?

Istnieje wiele dobrych odpowiedzi wyjaśniających, czym jest odwołanie zerowe i jak go debugować. Ale jest bardzo niewiele, jak zapobiec problemowi lub przynajmniej ułatwić złapanie.

Sprawdź argumenty

Na przykład metody mogą sprawdzić różne argumenty, aby sprawdzić, czy są one puste, i wygenerować ArgumentNullExceptionwyjątek, który oczywiście został stworzony w tym właśnie celu.

Konstruktor ArgumentNullExceptionparzystego przyjmuje nazwę parametru i komunikat jako argumenty, abyś mógł powiedzieć deweloperowi, na czym polega problem.

public void DoSomething(MyObject obj) {
    if(obj == null) 
    {
        throw new ArgumentNullException("obj", "Need a reference to obj.");
    }
}

Użyj narzędzi

Istnieje również kilka bibliotek, które mogą pomóc. Na przykład „Resharper” może dostarczyć ostrzeżeń podczas pisania kodu, zwłaszcza jeśli użyjesz ich atrybutu: NotNullAttribute

Istnieje „Microsoft Code Contracts”, w których używasz składni, Contract.Requires(obj != null)która zapewnia sprawdzanie czasu wykonywania i kompilacji: Wprowadzenie umów Code .

Istnieje również „PostSharp”, który pozwoli ci używać takich atrybutów:

public void DoSometing([NotNull] obj)

W ten sposób i włączenie PostSharp do procesu kompilacji objbędzie sprawdzane pod kątem zerowości w czasie wykonywania. Zobacz: Kontrola zerowa PostSharp

Rozwiązanie Plain Code

Lub zawsze możesz zakodować własne podejście, używając zwykłego starego kodu. Na przykład tutaj jest struktura, której można użyć do przechwytywania zerowych referencji. Jest wzorowany na tej samej koncepcji, co 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 };
    }
}

Użyłbyś bardzo podobnego do tego samego, którego używałbyś Nullable<T>, z wyjątkiem celu osiągnięcia dokładnie odwrotnej sytuacji - aby nie pozwolić null. Oto kilka przykładów:

NotNull<Person> person = null; // throws exception
NotNull<Person> person = new Person(); // OK
NotNull<Person> person = GetPerson(); // throws exception if GetPerson() returns null

NotNull<T>jest niejawnie przesyłany do iz miejsca, Tdzięki czemu można go używać niemal wszędzie tam, gdzie jest to potrzebne. Na przykład możesz przekazać Personobiekt do metody, która przyjmuje NotNull<Person>:

Person person = new Person { Name = "John" };
WriteName(person);

public static void WriteName(NotNull<Person> person)
{
    Console.WriteLine(person.Value.Name);
}

Jak widać powyżej, podobnie jak w przypadku wartości zerowej, można uzyskać dostęp do wartości bazowej za pośrednictwem Valuewłaściwości. Alternatywnie możesz użyć jawnej lub niejawnej rzutowania, możesz zobaczyć przykład z wartością zwracaną poniżej:

Person person = GetPerson();

public static NotNull<Person> GetPerson()
{
    return new Person { Name = "John" };
}

Możesz też użyć go, gdy metoda właśnie powraca T(w tym przypadku Person), wykonując rzut. Na przykład poniższy kod byłby podobny do powyższego:

Person person = (NotNull<Person>)GetPerson();

public static Person GetPerson()
{
    return new Person { Name = "John" };
}

Połącz z rozszerzeniem

W połączeniu NotNull<T>z metodą rozszerzenia możesz objąć jeszcze więcej sytuacji. Oto przykład, jak może wyglądać metoda rozszerzenia:

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

A oto przykład, jak można go użyć:

var person = GetPerson().NotNull();

GitHub

W celach informacyjnych udostępniłem powyższy kod na GitHub, można go znaleźć pod adresem:

https://github.com/luisperezphd/NotNull

Powiązana funkcja języka

W C # 6.0 wprowadzono „operator null-warunkowy”, który trochę w tym pomaga. Dzięki tej funkcji możesz odwoływać się do zagnieżdżonych obiektów i jeśli którykolwiek z nich nullzwraca całe wyrażenie null.

Zmniejsza to liczbę kontroli zerowych, które musisz wykonać w niektórych przypadkach. Składnia polega na umieszczeniu znaku zapytania przed każdą kropką. Weźmy na przykład następujący kod:

var address = country?.State?.County?.City;

Wyobraź sobie, że countryjest to obiekt typu, Countryktóry ma właściwość o nazwie Statei tak dalej. Jeśli country, State, County, lub Cityjest nullwtedy address will bezerowy . Therefore you only have to check whetheradresis null`.

To świetna funkcja, ale daje mniej informacji. Nie jest oczywiste, który z 4 jest pusty.

Wbudowany jak Nullable?

C # ma ładny skrót Nullable<T>, możesz zrobić coś null, umieszczając znak zapytania za takim typem int?.

Byłoby miło, gdyby C # miał coś w rodzaju NotNull<T>struktury powyżej miał podobny skrót, może wykrzyknik tak, że można napisać coś takiego (!) public void WriteName(Person! person).

Luis Perez
źródło
2
Nigdy nie rzucaj wyjątku NullReferenceException
John Saunders
@JohnSaunders odważę się zapytać dlaczego? (Poważnie, dlaczego?)
Luis Perez,
2
NullReferenceException ma być zgłaszany przez CLR. Oznacza to, że wystąpiło odwołanie do wartości null. Nie oznacza to, że wystąpiłoby odwołanie do wartości null, z wyjątkiem sprytnego sprawdzenia najpierw.
John Saunders,
Rozumiem twój punkt widzenia, w jaki sposób byłoby to mylące. Zaktualizowałem go do regularnego wyjątku dla tego przykładu i niestandardowego wyjątku w GitHub.
Luis Perez,
Świetna odpowiedź na tak podstawowe pytanie. Nie jest tak źle, gdy zawodzi Twój kod. To okropne, gdy pochodzi głęboko z jakiejś komercyjnej biblioteki strony trzeciej, na której polegasz, a obsługa klienta nieustannie nalega, aby przyczyną problemu był Twój kod. I nie do końca jesteś pewien, że tak nie jest, a cały projekt jest gotowy do zatrzymania. Myślę, że może to być odpowiednie epitafium dla mojego nagrobka: „Odwołanie do obiektu nie jest ustawione na instancję obiektu”.
Darrel Lee
10

Co ciekawe, żadna z odpowiedzi na tej stronie nie wspomina o dwóch przypadkach, mam nadzieję, że nikt nie będzie miał nic przeciwko, jeśli je dodam:

Edge case # 1: równoczesny dostęp do słownika

Słowniki ogólne w .NET nie są bezpieczne dla wątków i czasami mogą rzucać a, NullReferencea nawet (częściej), KeyNotFoundExceptiongdy próbujesz uzyskać dostęp do klucza z dwóch współbieżnych wątków. Wyjątek jest w tym przypadku dość mylący.

Edge case # 2: niebezpieczny kod

Jeśli kod NullReferenceExceptionjest rzucany przez a unsafe, możesz spojrzeć na zmienne wskaźnika i sprawdzić, IntPtr.Zeroczy nie. Co jest tym samym („wyjątek wskaźnika zerowego”), ale w niebezpiecznym kodzie zmienne są często rzutowane na typy wartości / tablice itp., A ty uderzasz głową o ścianę, zastanawiając się, jak typ wartości może to rzucić wyjątek.

(Nawiasem mówiąc, kolejny powód nieużywania niebezpiecznego kodu, chyba że jest on potrzebny)

jazzcat
źródło
5
Twój słownik nie jest przykładem krawędzi. Jeśli obiekt nie jest bezpieczny dla wątków, użycie go z wielu wątków daje losowe wyniki. Twój przykład niebezpiecznego kodu różni się nullw jaki sposób?
John Saunders
10

Możesz naprawić NullReferenceException w czysty sposób za pomocą Null-warunkowych operatorów w c # 6 i napisać mniej kodu do obsługi kontroli zerowej.

Służy do testowania wartości zerowej przed wykonaniem operacji dostępu do elementu (?.) Lub indeksu (? [).

Przykład

  var name = p?.Spouse?.FirstName;

jest równa:

    if (p != null)
    {
        if (p.Spouse != null)
        {
            name = p.Spouse.FirstName;
        }
    }

Rezultat jest taki, że nazwa będzie pusta, gdy p jest puste lub gdy p. Małżonek jest pusty.

W przeciwnym razie do nazwy zmiennej zostanie przypisana wartość p.Spouse.FirstName.

Aby uzyskać więcej informacji: Operatory warunkowe o wartości NULL

rozdział M.Hassan
źródło
9

Wiersz błędu „Odwołanie do obiektu nie jest ustawione na wystąpienie obiektu.” Stwierdza, że ​​nie przypisałeś obiektu wystąpienia do odwołania do obiektu i nadal masz dostęp do właściwości / metod tego obiektu.

na przykład: załóżmy, że masz klasę o nazwie myClass i zawiera ona jedną właściwość prop1.

public Class myClass
{
   public int prop1 {get;set;}
}

Teraz uzyskujesz dostęp do tego prop1 w innej klasie, tak jak poniżej:

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref.prop1 = 1;  //This line throws error
     }
}

powyższa linia zgłasza błąd, ponieważ zadeklarowano odwołanie do klasy myClass, ale nie zostało utworzone lub instancja obiektu nie jest przypisana do referencji tej klasy.

Aby to naprawić, musisz utworzyć instancję (przypisać obiekt do odwołania do tej klasy).

public class Demo
{
     public void testMethod()
     {
        myClass ref = null;
        ref = new myClass();
        ref.prop1 = 1;  
     }
}
Jaimin Dave
źródło
4

NullReferenceException lub odwołanie do obiektu nie ustawione na instancję obiektu występuje, gdy obiekt klasy, z której próbujesz skorzystać, nie jest tworzony. Na przykład:

Załóżmy, że masz klasę o nazwie Student.

public class Student
{
    private string FirstName;
    private string LastName;
    public string GetFullName()
    {
        return FirstName + LastName;
    }
}

Teraz rozważ inną klasę, w której próbujesz odzyskać pełne imię i nazwisko ucznia.

public class StudentInfo
{      
    public string GetStudentName()
    {
        Student s;
        string fullname = s.GetFullName();
        return fullname;
    }        
}

Jak widać w powyższym kodzie, instrukcja Student - deklaruje tylko zmienną typu Student, zauważ, że klasa Student nie jest w tym momencie tworzona. Dlatego gdy zostanie wykonana instrukcja s.GetFullName (), zgłosi wyjątek NullReferenceException.

Nacięcie
źródło
3

Cóż, w prostych słowach:

Próbujesz uzyskać dostęp do obiektu, który nie został utworzony lub nie znajduje się w pamięci.

Jak więc rozwiązać ten problem:

  1. Debuguj i pozwól, aby debugger się zepsuł ... To zabierze Cię bezpośrednio do zmiennej, która jest zepsuta ... Teraz Twoim zadaniem jest po prostu to naprawić .. Używając nowego słowa kluczowego w odpowiednim miejscu.

  2. Jeśli jest to spowodowane niektórymi poleceniami bazy danych , ponieważ obiekt nie jest obecny, wszystko, co musisz zrobić, to sprawdzić zerowo i obsłużyć go:

    if (i == null) {
        // Handle this
    }
  3. Najtrudniejszy ... jeśli GC już zebrał obiekt ... Z reguły dzieje się tak, jeśli próbujesz znaleźć obiekt za pomocą ciągów ... Znalezienie go po nazwie obiektu może się zdarzyć, że GC może już wyczyściłem go ... Jest to trudne do znalezienia i stanie się sporym problemem ... Lepszym sposobem na rozwiązanie tego problemu jest przeprowadzanie zerowych kontroli tam, gdzie jest to konieczne podczas procesu programowania. Zaoszczędzi ci to dużo czasu.

Przez znajdowanie po nazwie rozumiem, że niektóre ramy pozwalają FIndObjects za pomocą ciągów, a kod może wyglądać następująco: FindObject („ObjectName”);

Akash Chowdary
źródło
3
Jeśli masz odniesienie do obiektu, to GC nigdy go nie czyści
John Saunders
2
jeśli użyjesz czegoś takiego jak FindObject („nazwa obiektu”), GC nie będzie wiedział, że zamierzasz odświeżyć ten obiekt .. to właśnie próbowałem wyjaśnić .. mają miejsce w czasie wykonywania
Akash Gutha
2
Istnieje kilka platform, które zapewniają tę funkcjonalność w języku C #, takich jak Unity. pytanie nie ma nic wspólnego z BCl. Szukaj w Internecie przed krytyką, istnieje mnóstwo takich funkcji, a dla twoich uprzejmych informacji korzystam nawet z nich codziennie. Teraz powiedz mi, w jaki sposób odpowiedź nie ma sensu.
Akash Gutha
2
docs.unity3d.com/ScriptReference/… sprawdź link i popraw siebie mr.expert: p
Akash Gutha
Przykłady, które widziałem w twoim linku, przypisują wyniki GameObject.Find do pola członka. To jest odniesienie i GC nie zbierze go, dopóki nie zostanie zebrany obiekt zawierający.
John Saunders,
1

Dosłownie najłatwiejszy sposób na naprawienie wyjątku NullReferenceException ma dwa sposoby. Jeśli masz GameObject, na przykład z dołączonym skryptem i zmienną o nazwie rb (rigidbody), ta zmienna zacznie być zerowa po uruchomieniu gry.
To dlatego otrzymujesz NullReferenceException, ponieważ komputer nie ma danych przechowywanych w tej zmiennej.

Będę używał zmiennej RigidBody jako przykładu.
Możemy dodawać dane naprawdę łatwo na kilka sposobów:

  1. Dodaj RigidBody do swojego obiektu za pomocą AddComponent> Fizyka> Rigidbody
    Następnie przejdź do skryptu i wpisz rb = GetComponent<Rigidbody>();
    Ten wiersz kodu działa najlepiej pod twoim Start()lub Awake()funkcjami.
  2. Możesz dodać komponent programowo i przypisać zmienną w tym samym czasie za pomocą jednego wiersza kodu: rb = AddComponent<RigidBody>();

Dalsze uwagi: Jeśli chcesz, aby jedność [RequireComponent(typeof(RigidBody))]dodała komponent do twojego obiektu i mogłeś zapomnieć o dodaniu jednego, możesz wpisać powyżej deklaracji klasy (miejsce poniżej wszystkich twoich zastosowań).
Ciesz się i baw się dobrze tworząc gry!

CausticLasagne
źródło
-1

Jeśli weźmiemy pod uwagę typowe scenariusze, w których ten wyjątek może zostać zgłoszony, uzyskujemy dostęp do właściwości z obiektem na górze.

Dawny:

string postalcode=Customer.Address.PostalCode; 
//if customer or address is null , this will through exeption

tutaj, jeśli adres ma wartość NULL, otrzymasz NullReferenceException.

Tak więc, jako praktyka, powinniśmy zawsze używać sprawdzania wartości zerowej, zanim uzyskamy dostęp do właściwości w takich obiektach (szczególnie w ogólności)

string postalcode=Customer?.Address?.PostalCode;
//if customer or address is null , this will return null, without through a exception
Hiran
źródło
-3

Jest to w zasadzie wyjątek odniesienia Null . Jak Microsoft Zjednoczonych byli

Wyjątek NullReferenceException jest zgłaszany, gdy próbujesz uzyskać dostęp do elementu typu, którego wartość jest równa null.

Co to znaczy?

Oznacza to, że jeśli jakikolwiek członek, który nie ma żadnej wartości, a my zmuszamy tego członka do wykonania określonego zadania, to system bez wątpienia wyrzuci wiadomość i powie:

„Hej, czekaj, ten członek nie ma wartości, więc nie może wykonać zadania, które mu przekazujesz”.

Sam wyjątek mówi, że coś jest odsyłane, ale którego wartość nie jest ustawiana. Oznacza to, że występuje tylko podczas używania typów odwołań, ponieważ typów wartości nie można zerować.

NullReferenceException nie wystąpi, jeśli używamy elementów typu Value.

class Program
{
    static void Main(string[] args)
    {
        string str = null;
        Console.WriteLine(str.Length);
        Console.ReadLine();
    }
}

Powyższy kod pokazuje prosty ciąg znaków, któremu przypisano null wartość .

Teraz, gdy próbuję wydrukować długość łańcucha str , pojawia się komunikat Nieobsługiwany wyjątek typu „System.NullReferenceException”, ponieważ element str pojawia się wskazuje na null i nie może być żadnej długości null.

NullReferenceException ” występuje również wtedy, gdy zapomnimy utworzyć instancję typu odwołania.

Załóżmy, że mam w nim metodę klasy i członka. Nie utworzyłem instancji mojej klasy, a jedynie jej nazwę. Teraz, jeśli spróbuję użyć tej metody, kompilator wyśle ​​błąd lub wygeneruje ostrzeżenie (w zależności od kompilatora).

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

    }
}

Kompilator powyższego kodu generuje błąd polegający na tym, że zmienna obj nie jest przypisana, co oznacza, że ​​nasza zmienna ma wartości zerowe lub nie ma jej wcale. Kompilator powyższego kodu generuje błąd polegający na tym, że zmienna obj nie jest przypisana, co oznacza, że ​​nasza zmienna ma wartości zerowe lub nie ma jej wcale.

Dlaczego tak się dzieje?

  • Wyjątek NullReferenceException powstaje z powodu naszej winy za nie sprawdzenie wartości obiektu. Często pozostawiamy wartości obiektów niezaznaczone w rozwoju kodu.

  • Powstaje również, gdy zapomnimy utworzyć instancję naszych obiektów. Przyczyną tego wyjątku może być także użycie metod, właściwości, kolekcji itp., Które mogą zwracać lub ustawiać wartości zerowe.

Jak można tego uniknąć?

Istnieją różne sposoby i metody unikania tego znanego wyjątku:

  1. Jawne sprawdzanie: powinniśmy przestrzegać tradycji sprawdzania obiektów, właściwości, metod, tablic i kolekcji, czy są one zerowe. Można to po prostu zaimplementować za pomocą instrukcji warunkowych, takich jak if-else if-else itp.

  2. Obsługa wyjątków: Jeden z ważnych sposobów zarządzania tym wyjątkiem. Za pomocą prostych bloków try-catch-wreszcie możemy kontrolować ten wyjątek, a także prowadzić jego rejestr. Może to być bardzo przydatne, gdy aplikacja jest na etapie produkcji.

  3. Operatory zerowe: Operator koalescencji zerowej i operatory warunkowe zerowe mogą być również przydatne podczas ustawiania wartości obiektów, zmiennych, właściwości i pól.

  4. Debuger: dla programistów mamy wielką broń podczas debugowania. Jeśli napotkamy NullReferenceException podczas obliczeń programistycznych, możemy użyć debuggera, aby dostać się do źródła wyjątku.

  5. Metoda wbudowana: metody systemowe, takie jak GetValueOrDefault (), IsNullOrWhiteSpace () i IsNullorEmpty () sprawdzają wartości null i przypisują wartość domyślną, jeśli istnieje wartość null.

Istnieje już wiele dobrych odpowiedzi. Możesz także sprawdzić bardziej szczegółowy opis z przykładami na moim blogu .

Mam nadzieję, że to też pomaga!

Wasim
źródło
Zasadniczo skopiowałeś połowę tego posta na blogu i nie dodałeś nic nowego, na co nie odpowiedzieli istniejące odpowiedzi.
CodeCaster,
@codecaster Czy powiedziano o kopiowaniu podczas przepisywania podsumowania z własnego bloga. Wiem, że w mojej odpowiedzi nie ma nic nowego i nic nowego, czego nie ma w poprzednich odpowiedziach, ale chcę przyczynić się w bardziej wyrafinowany sposób i pozwolić innym zrozumieć sposób, w jaki rozumiem. Będzie zadowolony, nawet jeśli pomoże to jednej osobie. W dobrej wierze.
Wasim
-4

Jeśli otrzymujesz ten komunikat podczas zapisywania lub kompilacji kompilacji, po prostu zamknij wszystkie pliki, a następnie otwórz dowolny plik, aby skompilować i zapisać.

Dla mnie powodem było to, że zmieniłem nazwę pliku i stary plik był nadal otwarty.

Harshal Doshi Jain
źródło