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 nullw metodzie „A”, może to oznaczać, że metoda „B” przekazała metodę nulldo „A”.
null może mieć różne znaczenia:
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.
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 NullReferenceExceptionzawsze 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:
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
publicclassPerson{publicintAge{get;set;}}publicclassBook{publicPersonAuthor{get;set;}}publicclassExample{publicvoidFoo(){Book b1 =newBook();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 =newBook{Author={Age=45}};
To przekłada się na
Book b1 =newBook();
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 .
Kolekcja zagnieżdżona Initializerszachowuje się tak samo:
Person p1 =newPerson{Books={newBook{Title="Title1"},newBook{Title="Title2"},}};
To przekłada się na
Person p1 =newPerson();
p1.Books.Add(newBook{Title="Title1"});
p1.Books.Add(newBook{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 =newPerson[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 =newlong[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)
publicclassPerson{publicstringName{get;set;}}var people =newList<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
publicclassDemo{publiceventEventHandlerStateChanged;protectedvirtualvoidOnStateChanged(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.
Można to rozwiązać, postępując zgodnie z konwencją, aby poprzedzać pola znakiem podkreślenia:
privateCustomer _customer;
Cykl życia strony ASP.NET:
publicpartialclassIssues_Edit:System.Web.UI.Page{protectedTestIssue myIssue;protectedvoidPage_Load(object sender,EventArgs e){if(!IsPostBack){// Only called on first load, not when button clicked
myIssue =newTestIssue();}}protectedvoidSaveButton_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 NullReferenceExceptionstring 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:
// ControllerpublicclassRestaurant:Controller{publicActionResultSearch(){returnView();// Forgot the provide a Model here.}}// Razor view @foreach(var restaurantSearch inModel.RestaurantSearch)// Throws.{}<p>@Model.somePropertyName</p><!--Alsothrows-->
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 --><ComboBoxName="comboBox1"Margin="10"SelectedIndex="0"SelectionChanged="comboBox1_SelectionChanged"><ComboBoxItemContent="Item 1"/><ComboBoxItemContent="Item 2"/><ComboBoxItemContent="Item 3"/></ComboBox><!-- Label declared later --><LabelName="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.
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 asThing;
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:
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ą:
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:
stringGetCategory(string bookTitle){var book = library.FindBook(bookTitle);// This may return nullif(book ==null)thrownewBookNotFoundException(bookTitle);// Your custom exceptionreturn 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:
stringGetTitle(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 codereturn 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 =newDateTime(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:
IServiceCreateService(ILogger log,Int32? frobPowerLevel){var serviceImpl =newMyService(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 checkint titleLength =0;if(title !=null)
titleLength = title.Length;// If title is null, this would throw NullReferenceException// combining the `?` and the `??` operatorint titleLength = title?.Length??0;
Podobnie, w przypadku tablic można używać ?[i]w następujący sposób:
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:
publicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){for(int i =0; i < count;++i)yieldreturn 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 THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){if(f ==null)thrownewArgumentNullException("f","factory must not be null");for(int i =0; i < count;++i)yieldreturn 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 THISpublicIEnumerable<Frob>GetFrobs(FrobFactory f,int count){// No yields in a public method that throws!if(f ==null)thrownewArgumentNullException("f","factory must not be null");returnGetFrobsForReal(f, count);}privateIEnumerable<Frob>GetFrobsForReal(FrobFactory f,int count){// Yields in a private methodDebug.Assert(f !=null);for(int i =0; i < count;++i)yieldreturn 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.
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:
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.
Przykłady (z postów przepełnienia stosu) nie zawsze pokazują najlepszy sposób zrobienia czegoś w pierwszej kolejności.
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.
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.
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 AsNew 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:
Uwaga: Nie używaj Dimponownie w procedurze, łącznie z konstruktorem ( Sub New):
Private reg As CashRegister
'...PublicSubNew()'...Dim reg AsNew CashRegister
EndSub
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 .
Ta tablica została tylko zadeklarowana, a nie utworzona. Istnieje kilka sposobów inicjalizacji tablicy:
Private arr asString()=NewString(10){}' orPrivate arr()AsString=NewString(10){}' For a local array (in a procedure) and using 'Option Infer':Dim arr =NewString(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 AsDouble()={1.5,2,9.9,18,3.14}Dim myDbl =NewDouble(){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 AsDouble()={1.5,2,9.9,18,3.14}
Przykład: tablica obiektów klasy
Dim arrFoo(5)As Foo
For i AsInteger=0To arrFoo.Count -1
arrFoo(i).Bar = i *10' ExceptionNext
Tablica została utworzona, ale Fooobiektów w niej nie ma.
Zaradzić
For i AsInteger=0To arrFoo.Count -1
arrFoo(i)=New Foo()' Create Foo instance
arrFoo(i).Bar = i *10Next
Użycie a List(Of T)utrudni posiadanie elementu bez ważnego obiektu:
Dim FooList AsNew List(Of Foo)' List created, but it is emptyDim f As Foo ' Temporary variable for the loopFor i AsInteger=0To5
f =New Foo()' Foo instance created
f.Bar = i *10
FooList.Add(f)' Foo object added to listNext
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 AsNew List(Of String)
Częstym nadzorem jest klasa, która korzysta z kolekcji Type:
PublicClass Foo
Private barList As List(Of Bar)FriendFunction BarCount AsIntegerReturn barList.Count
EndFunctionFriendSub AddItem(newBar As Bar)If barList.Contains(newBar)=FalseThen
barList.Add(newBar)EndIfEndFunction
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:
PublicSubNew' Constructor' Stuff to do when a new Foo is created...
barList =New List(Of Bar)EndSub
Tak jak poprzednio, jest to nieprawidłowe:
PublicSubNew()' Creates another barList local to this procedureDim barList AsNew List(Of Bar)EndSub
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 AsInteger
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ć:
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ń.
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 >0Then
txtID.Text = ds.Tables(0).Rows(0).Item(1)
txtID.Name = ds.Tables(0).Rows(0).Item(2)EndIf
Filljest funkcją zwracającą liczbę Rowsdotkniętych, które można również przetestować:
If da.Fill(ds,"Employees")>0Then...
Przykład 3
Dim da AsNew 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 AsNew DataSet
da.Fill(ds)If ds.Tables("TICKET_RESERVATION").Rows.Count >0Then
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:
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:
Tutaj, myWebBrowserlub Documentmoże być nic lub formfld1element nie może istnieć.
Kontrolki interfejsu użytkownika
Dim cmd5 AsNew 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 validationIf(ComboBox5.SelectedItems.Count >0)AndAlso(ListBox1.SelectedItems.Count >0)AndAlso(ComboBox2.SelectedItems.Count >0)AndAlso(DateTime.TryParse(expiry.Text, expiry)Then'... do stuffElse
MessageBox.Show(...error message...)EndIf
PublicClass 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 AsNew List(Of TextBox) From {TextBox1, TextBox2, TextBox3 ...}' Immediate NRE:Private somevar AsString=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 AsString= NameBoxes(2).Text ' NRE' ...' More code (which will likely not be executed)' ...EndSub
Uwaga: dotyczy to wszystkich odniesień do kontroli i komponentów, które czynią je nielegalnymi, gdy są:
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 declarationPrivate NameBoxes as TextBox()Private studentName AsString' 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:
„Button2” znajduje się na Panel
Zaradzić
Zamiast pośrednich odniesień według nazwy przy użyciu Controlskolekcji formularza , użyj odwołania kontrolnego:
' DeclarationPrivate 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 AsNew List(Of Bars)' Declared and createdPublicFunction BarList()As List(Of Bars)
bars.Clear
If someCondition ThenFor n AsInteger=0to someValue
bars.Add(GetBar(n))Next n
ElseExitFunctionEndIfReturn bars
EndFunction
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()ForEach b As Bar in bList ' EXCEPTION...
Zaradzić
Zamień Exit Functionw funkcji na Return bList. Zwracanie pustegoList nie jest tym samym, co zwracanie Nothing. Jeśli istnieje szansa, że zwrócony obiekt może być Nothing, przetestuj go przed użyciem:
Źle zaimplementowana funkcja Try / Catch może ukryć problem i doprowadzić do powstania nowych:
Dim dr As SqlDataReader
TryDim lnk As LinkButton = TryCast(sender, LinkButton)Dim gr As GridViewRow =DirectCast(lnk.NamingContainer, GridViewRow)Dim eid AsString= 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()EndIf
command =New SqlCommand(sqlQry, connection)'More code fooing and barring
dr = command.ExecuteReader()If dr.Read()Then
lblFirstName.Text = Convert.ToString(dr("FirstName"))...EndIf
mpe.Show()CatchFinally
command.Dispose()
dr.Close()' <-- NRE
connection.Close()EndTry
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
ForEach row As DataGridViewRow In dgvPlanning.Rows
IfNot 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 NothingThen...
Tak jak poprzednio, możesz przetestować na Nic, a następnie na określoną wartość:
Dim getFoo =(From f In dbContext.FooBars
Where f.something = something
Select f).FirstOrDefault
IfNot IsDBNull(getFoo)ThenIf 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 NothingThen...
Sterownica
Dim chk As CheckBox
chk =CType(Me.Controls(chkName), CheckBox)If chk.Checked ThenReturn chk
EndIf
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.
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:
ForEach r As DataGridViewRow in myDGV.Rows
If r.IsNewRow =FalseThen' 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 IsNothingThen
My.Settings.FooBars =New System.Collections.Specialized.StringCollection
EndIf
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).
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:
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 ...
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:
Zawsze inicjuj swoje obiekty, zanim spróbujesz cokolwiek z nimi zrobić.
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.
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}
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.
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.
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ść.
-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 :
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:
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:
stringvalue=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 ()
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.
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
object o =null;DateTime d =(DateTime)o;// NullReferenceException
gdzie unboxing konwersji (cast) zobject (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 falsez 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:
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 =newContact{Name="Abhinav"};var context =newDataContext();
context.Contacts.Add(contact);
context.SaveChanges();// NullReferenceException at this line
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.
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.
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.
publicclassMyController{privateServiceA serviceA;privateServiceB serviceB;publicMyController(ServiceA serviceA,ServiceB serviceB){this.serviceA = serviceA;this.serviceB = serviceB;}publicvoidMyMethod(){// 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();}}
-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;}publicvoidInvokeX(){
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]protectedvoidObjectInvariant(){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 .
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.
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.
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 =newMyEntity();}@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 =newMyEntity();}@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:
@inheritsSystem.Web.Mvc.WebViewPage@{ViewBag.Title="Entity Index";List<MyEntity>MyEntities=newList<MyEntity>();MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());MyEntities.Add(newMyEntity());}<div>@{foreach(var M inMyEntities){// 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 inMyEntities){...}
Chociaż mam wrażenie, że było tak, ponieważ Visual Studio źle odczytał znaki handlowe i nawiasy klamrowe.
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.
publicvoidDoSomething(MyObject obj){if(obj ==null){thrownewArgumentNullException("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:
publicvoidDoSometing([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]publicstructNotNull<T>where T:class{private T _value;public T Value{get{if(_value ==null){thrownewException("null value not allowed");}return _value;}set{if(value==null){thrownewException("null value not allowed.");}
_value =value;}}publicstaticimplicitoperator T(NotNull<T> notNullValue){return notNullValue.Value;}publicstaticimplicitoperatorNotNull<T>(T value){returnnewNotNull<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 exceptionNotNull<Person> person =newPerson();// OKNotNull<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 =newPerson{Name="John"};WriteName(person);publicstaticvoidWriteName(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();publicstaticNotNull<Person>GetPerson(){returnnewPerson{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();publicstaticPersonGetPerson(){returnnewPerson{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]publicstaticclassNotNullExtension{publicstatic T NotNull<T>(this T @this)where T:class{if(@this==null){thrownewException("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:
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).
@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)
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.
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.
publicClass myClass
{publicint prop1 {get;set;}}
Teraz uzyskujesz dostęp do tego prop1 w innej klasie, tak jak poniżej:
publicclassDemo{publicvoid 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).
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:
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.
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:
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.
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}
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”);
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.
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:
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.
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!
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
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.
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).
classProgram{staticvoidMain(string[] args){MyClass1 obj;
obj.foo();//Use of unassigned local variable 'obj'}}publicclassMyClass1{internalvoid 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:
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.
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.
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.
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.
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 .
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.
Odpowiedzi:
Jaka jest przyczyna?
Dolna linia
Próbujesz użyć czegoś, co jest
null
(lubNothing
w VB.NET). Oznacza to, że albo go ustawisznull
, albo nigdy nie ustawisz go na niczym.Jak wszystko inne,
null
zostaje przekazany. Jeśli jestnull
w metodzie „A”, może to oznaczać, że metoda „B” przekazała metodęnull
do „A”.null
może mieć różne znaczenia:NullReferenceException
.null
celowo, 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ćnull
do nich, aby wskazać, że nie ma w nim żadnej wartości, na przykładint? a = null;
tam, gdzie znak zapytania wskazuje, że może przechowywać null zmiennaa
. Możesz to sprawdzić za pomocąif (a.HasValue) {...}
lub za pomocąif (a==null) {...}
. Zmienne dopuszczające wartości zerowe, takie jaka
ten przykład, umożliwiają dostęp do wartościa.Value
jawnie lub tak samo normalnie przeza
.Zauważ, że dostęp do niego przez
a.Value
rzucaInvalidOperationException
zamiast zamiastNullReferenceException
jeślia
Isnull
- powinieneś zrobić to wcześniej, tzn. jeśli masz inną zmienną nullableint b;
, powinieneś wykonywać zadania takie jakif (a.HasValue) { b = a.Value; }
lub krótszeif (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
runtime
RzucanieNullReferenceException
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
null
i nie można uzyskać dostępu do członków (takich jak metody) poprzeznull
referencję. Najprostszy przypadek:Spowoduje to wyrzucenie a
NullReferenceException
w drugiej linii, ponieważ nie można wywołać metody instancjiToUpper()
dlastring
odwoł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
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:W szczególności, w
HttpContext.Current.User.Identity.Name
TheHttpContext.Current
może być zerowa lubUser
nieruchomość może być null, lubIdentity
nieruchomość może być zerowa.Pośredni
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:
To przekłada się na
Gdy
new
używane jest słowo kluczowe, tworzy ono tylko nowe wystąpienieBook
, ale nie nowePerson
, więcAuthor
właściwość jest nadalnull
.Inicjatory kolekcji zagnieżdżonych
Kolekcja zagnieżdżona
Initializers
zachowuje się tak samo:To przekłada się na
new Person
Tylko tworzy instancjęPerson
, aleBooks
kolekcja jest nadalnull
.Initializer
Składnia kolekcji nie tworzy kolekcjip1.Books
, tylko tłumaczy nap1.Books.Add(...)
instrukcje.Szyk
Elementy tablicy
Jagged Arrays
Kolekcja / Lista / Słownik
Zakres zmiennej (pośredni / odroczony)
Wydarzenia
klasa publiczna Form1 {klient prywatny;
}
Można to rozwiązać, postępując zgodnie z konwencją, aby poprzedzać pola znakiem podkreślenia:
Cykl życia strony ASP.NET:
Wartości sesji ASP.NET
Modele pustego widoku ASP.NET MVC
Jeśli wystąpi wyjątek podczas odwoływania się do właściwości
@Model
wASP.NET MVC View
, musisz zrozumieć, żeModel
metoda ustawia się w metodzie akcji podczasreturn
przeglą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:Kolejność tworzenia kontroli WPF i zdarzenia
WPF
formanty są tworzone podczas połączeniaInitializeComponent
w kolejności, w jakiej pojawiają się w drzewie wizualnym. ANullReferenceException
zostanie podniesiony w przypadku wcześniej utworzonych elementów sterujących za pomocą procedur obsługi zdarzeń itp.,InitializeComponent
Które uruchamiają się, podczas których odwołują się elementy sterujące utworzone wcześniej.Na przykład :
Tutaj
comboBox1
jest tworzony wcześniejlabel1
. JeślicomboBox1_SelectionChanged
spróbujesz odwołać się do `label1, nie zostanie jeszcze utworzona.Zmiana kolejności deklaracji w
XAML
(tj. Umieszczenielabel1
wcześniejcomboBox1
, ignorowanie kwestii filozofii projektowania, przynajmniej rozwiązałoby problemNullReferenceException
tutaj.Obsada z
as
Nie rzuca to,
InvalidCastException
ale zwraca a,null
gdy rzutowanie się nie powiedzie (i gdysomeObject
sam jest pusty). Więc bądź tego świadomy.LINQ
FirstOrDefault()
iSingleOrDefault()
Proste wersje
First()
iSingle()
wyjątki, gdy nic nie ma. W takim przypadku wersje „OrDefault” zwracają wartość null. Więc bądź tego świadomy.dla każdego
foreach
rzuca, gdy próbujesz iterować pustą kolekcję. Zwykle spowodowane przez nieoczekiwanynull
wynik metod zwracających kolekcje.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:
Sposoby, których należy unikać
Jawnie sprawdź
null
i zignoruj wartości puste.Jeśli spodziewasz się, że odwołanie ma czasami wartość NULL, możesz sprawdzić, czy istnieje ono
null
przed uzyskaniem dostępu do członków instancji:Jawnie sprawdź
null
i 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ą:Jawnie sprawdź
null
wywoł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:
Użyj,
Debug.Assert
jeś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:Chociaż to sprawdzenie nie zakończy się w kompilacji wydania , co spowoduje, że wyrzuci go
NullReferenceException
ponownie, gdy będziebook == null
w środowisku uruchomieniowym w trybie wydania.Użyj
GetValueOrDefault()
dlanullable
typów wartości, aby podać wartość domyślną, gdy sąnull
.Użyj zerowego operatora koalescencyjnego:
??
[C #] lubIf()
[VB].Skrót do podania wartości domyślnej w przypadku
null
napotkania: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:
Jeśli dana osoba nie ma tytułu, spowoduje to zgłoszenie wyjątku, ponieważ próbuje ona wywołać
ToUpper
właściwość o wartości zerowej.W
C# 5
i poniżej, może to być strzeżone z:Teraz zmienna tytułowa będzie miała wartość NULL zamiast zgłaszać wyjątek. C # 6 wprowadza krótszą składnię do tego:
Spowoduje to powstanie zmiennej tytułowej
null
, a wywołanie doToUpper
nie zostanie wykonane, jeśli takperson.Title
jestnull
.Oczywiście nadal musisz sprawdzić
title
wartość null lub użyć operatora warunku zerowego razem z operatorem koalescencji zerowej (??
), aby podać wartość domyślną:Podobnie, w przypadku tablic można używać
?[i]
w następujący sposób:Spowoduje to wykonanie następujących czynności: Jeśli
myIntArray
jest null, wyrażenie zwraca null i można go bezpiecznie sprawdzić. Jeśli zawiera tablicę, zrobi to samo co:elem = myIntArray[i];
i zwrócii<sup>th</sup>
element.Użyj kontekstu zerowego (dostępny w C # 8):
Wprowadzone
C# 8
tam 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ą
Nullable
elementu zcsproj
pliku. Ten element konfiguruje sposób, w jaki kompilator interpretuje zerowanie typów oraz generowane ostrzeżenia. Prawidłowe ustawienia to: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:Jeśli
whatever
wyniki wnull
toMakeFrob
rzuci. Teraz możesz pomyśleć, że właściwą rzeczą jest:Dlaczego to źle? Ponieważ blok iteratora tak naprawdę nie działa aż do
foreach
! WywołanieGetFrobs
po 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:
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
GetFrobs
jest wywoływany, sprawdzanie wartości zerowej odbywa się natychmiast, a następnieGetFrobsForReal
wykonuje się, gdy sekwencja jest iterowana.Jeśli sprawdzisz źródło odniesienia
LINQ
do 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:
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ę
CLR
cał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.
źródło
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?Wyjątek NullReference - Visual Basic
NullReference Exception
Dla 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:
NullReferenceException
(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.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:
Znalezienie przyczyny
Ponieważ problemem jest odwołanie do obiektu, dlatego
Nothing
odpowiedzią 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ędzieNothing
.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
MsgBox
in 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
Problem polega na tym,
Dim
że nie tworzy obiektu CashRegister ; deklaruje tylko zmiennąreg
tego typu. Zadeklarowanie zmiennej obiektu i utworzenie instancji to dwie różne rzeczy.Zaradzić
New
Operator często mogą być wykorzystywane do tworzenia instancji, gdy zadeklarujesz go:Jeśli odpowiednie jest utworzenie instancji później:
Uwaga: Nie używaj
Dim
ponownie w procedurze, łącznie z konstruktorem (Sub New
):Spowoduje to utworzenie zmiennej lokalnej
reg
, która istnieje tylko w tym kontekście (pod).reg
Zmiennej z poziomu modułuScope
, który będzie używany wszędzie indziej szczątkiNothing
.Dla jasności
Dim
(lubPrivate
) 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 | Public
określa poziom dostępu, a nie zakres .Aby uzyskać więcej informacji, zobacz:
Tablice
Tablice muszą być również tworzone:
Ta tablica została tylko zadeklarowana, a nie utworzona. Istnieje kilka sposobów inicjalizacji tablicy:
Uwaga: Począwszy od VS 2010, podczas inicjowania tablicy lokalnej za pomocą literału
Option Infer
, elementyAs <Type>
iNew
są opcjonalne:Typ danych i rozmiar tablicy są wywnioskowane z przypisywanych danych. Deklaracje poziomie modułu / klasa nadal wymagają
As <Type>
zOption Strict
:Przykład: tablica obiektów klasy
Tablica została utworzona, ale
Foo
obiektów w niej nie ma.Zaradzić
Użycie a
List(Of T)
utrudni posiadanie elementu bez ważnego obiektu: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.
Otrzymujesz ten sam wyjątek z tego samego powodu -
myList
został tylko zadeklarowany, ale nie utworzono żadnej instancji. Środek zaradczy jest taki sam:Częstym nadzorem jest klasa, która korzysta z kolekcji
Type
:Każda z procedur spowoduje NRE, ponieważ
barList
jest tylko deklarowana, a nie tworzona. Utworzenie wystąpieniaFoo
nie spowoduje również utworzenia wystąpienia wewnętrznegobarList
. Być może zamierzano to zrobić w konstruktorze:Tak jak poprzednio, jest to nieprawidłowe:
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
Tak jak poprzednio
ds
obiekt Dataset został zadeklarowany, ale instancja nigdy nie została utworzona.DataAdapter
Wypełni istniejącąDataSet
, nie utworzyć. W tym przypadku, ponieważds
jest to zmienna lokalna, IDE ostrzega, że może się to zdarzyć: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ć
Przykład 2
Literówka jest problemem tutaj:
Employees
vsEmployee
. NieDataTable
utworzono nazwy „Pracownik”, więcNullReferenceException
wyniki próbują uzyskać do niej dostęp. Innym potencjalnym problemem jest założenie, żeItems
nie będzie, gdy SQL zawiera klauzulę WHERE.Zaradzić
Ponieważ używa to jednej tabeli, użycie
Tables(0)
pozwoli uniknąć błędów ortograficznych. BadanieRows.Count
może również pomóc:Fill
jest funkcją zwracającą liczbęRows
dotkniętych, które można również przetestować:Przykład 3
DataAdapter
ZapewniTableNames
jak 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:
Zobacz także klasę DataTable .
Ścieżki do obiektu / zagnieżdżone
Kod testuje tylko
Items
oba elementymyFoo
iBar
może być również niczym. Lekarstwem jest sprawdzenie całego łańcucha lub ścieżkę obiektów jednym na raz:AndAlso
jest ważne. Kolejne testy nie zostaną wykonane poFalse
spełnieniu pierwszego warunku. Pozwala to kodowi bezpiecznie „wiercić” w obiekcie (ach) jeden „poziom” na raz, oceniającmyFoo.Bar
dopiero po (i jeśli)myFoo
ustaleniu, że jest poprawny. Łańcuchy obiektów lub ścieżki mogą być dość długie podczas kodowania złożonych obiektów:Nie można odwoływać się do niczego „poniżej”
null
obiektu. Dotyczy to również kontroli:Tutaj,
myWebBrowser
lubDocument
może być nic lubformfld1
element nie może istnieć.Kontrolki interfejsu użytkownika
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.SelectedItem
może byćNothing
, więcListBox1.SelectedItem.ToString
spowoduje NRE.Zaradzić
Sprawdź poprawność danych przed ich użyciem (także
Option Strict
parametrami use i SQL):Alternatywnie możesz użyć
(ComboBox5.SelectedItem IsNot Nothing) AndAlso...
Formy Visual Basic
Jest to dość powszechny sposób na uzyskanie NRE. W języku C #, w zależności od sposobu kodowania, IDE zgłosi, że
Controls
nie 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
Form
lubControls
. W rezultacie:somevar
Przypisanie spowoduje natychmiastowego NRE bo nic nie posiada.Text
własnośćOdwołanie do elementów tablicy później spowoduje NRE. Jeśli zrobisz to z
Form_Load
powodu 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 New
lubForm Load
zdarzenia), wyjątki mogą nie zostać zgłoszone, kod kończy procedurę i wyświetla tylko formularz.Ponieważ żaden inny kod w Twoim
Sub New
lubForm Load
zdarzeniu nie będzie działał po NRE, wiele innych rzeczy może pozostać niezainicjowanych.Uwaga: dotyczy to wszystkich odniesień do kontroli i komponentów, które czynią je nielegalnymi, gdy są:
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 New
dopóki kod jest poInitializeComponent
wywołaniu:Kod tablicy może jeszcze nie wyjść z lasu. Wszelkie formanty znajdujące się w kontrolce kontenera (jak a
GroupBox
lubPanel
) nie zostaną znalezione wMe.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 przypadkachNothing
ponownie 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:
„Button2” znajduje się na
Panel
Zaradzić
Zamiast pośrednich odniesień według nazwy przy użyciu
Controls
kolekcji formularza , użyj odwołania kontrolnego:Funkcja nic nie zwraca
Jest to przypadek, w którym IDE ostrzega, że „ nie wszystkie ścieżki zwracają wartość i
NullReferenceException
może wynikać ”. Możesz wyłączyć ostrzeżenie, zastępującExit Function
jeReturn Nothing
, ale to nie rozwiązuje problemu. Wszystko, co próbuje użyć return, kiedysomeCondition = False
spowoduje NRE:Zaradzić
Zamień
Exit Function
w funkcji naReturn bList
. Zwracanie pustegoList
nie jest tym samym, co zwracanieNothing
. Jeśli istnieje szansa, że zwrócony obiekt może byćNothing
, przetestuj go przed użyciem:Źle zaimplementowane Try / Catch
Źle zaimplementowana funkcja Try / Catch może ukryć problem i doprowadzić do powstania nowych:
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,Catch
jak nic nie robi,Finally
próbuje wykonać czyszczenie, ale ponieważ nie możnaClose
wyzerowaćDataReader
obiektu, wyniki są zupełnie noweNullReferenceException
.Pusty
Catch
blok to diabelski plac zabaw. Ten PO był zaskoczony, dlaczego dostaje NRE wFinally
bloku. W innych sytuacjach pustaCatch
moż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
IsDBNull
Funkcja służy do sprawdzania, czy dana wartość jest równaSystem.DBNull
: Od MSDN:Zaradzić
Tak jak poprzednio, możesz przetestować na Nic, a następnie na określoną wartość:
Przykład 2
FirstOrDefault
zwraca pierwszy element lub wartość domyślną, która dotyczyNothing
typów referencyjnych i nigdyDBNull
:Sterownica
Jeżeli
CheckBox
zechkName
nie można znaleźć (lub istnieje wGroupBox
), wówczaschk
będzie nic i być próbuje odwołać każdą własność spowoduje wyjątek.Zaradzić
DataGridView
DGV ma okresowo kilka dziwactw:
Jeśli
dgvBooks
takAutoGenerateColumns = 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:
Przykład 2 - Strzeż się NewRow
Gdy twój
DataGridView
maAllowUserToAddRows
jakoTrue
(domyślny), wszystkieCells
w pustym / nowym wierszu na dole będą zawieraćNothing
. Większość prób użycia zawartości (na przykładToString
) spowoduje NRE.Zaradzić
Użyj
For/Each
pętli i przetestujIsNewRow
właściwość, aby ustalić, czy jest to ostatni wiersz. DziałaAllowUserToAddRows
to niezależnie od tego, czy jest prawdziwe:Jeśli używasz
For n
pętli, zmień liczbę wierszy lub użyj,Exit For
gdyIsNewRow
jest to prawda.My.Settings (StringCollection)
W pewnych okolicznościach próba użycia elementu, z
My.Settings
którego jest,StringCollection
może spowodować NullReference przy pierwszym użyciu. Rozwiązanie jest takie samo, ale nie tak oczywiste. Rozważać: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,
Nothing
gdy nie ma żadnych elementów w edytorze ustawień do dodania.Zaradzić
Zainicjuj kolekcję ustawień w
Load
module obsługi zdarzeń formularza , jeśli / w razie potrzeby:Zazwyczaj
Settings
kolekcję 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ś
New
operatora.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
źródło
Innym scenariuszem jest rzutowanie pustego obiektu na typ wartości . Na przykład poniższy kod:
Rzuci a
NullReferenceException
na 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:
Tutaj,
SelectedDate
w rzeczywistości jest nieruchomość - odDateTime
typu - oCalendar
kontroli 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 ...źródło
DateTime x = (DateTime) o as DateTime? ?? defaultValue;
Oznacza to, że dana zmienna nie jest wskazywana na nic. Mógłbym to wygenerować tak:
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:
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.
źródło
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.
źródło
Należy pamiętać, że niezależnie od scenariusza przyczyna jest zawsze taka sama w .NET:
źródło
Przykład zgłaszanego wyjątku to: Gdy próbujesz coś sprawdzić, jest to zerowe.
Na przykład:
Ś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 .
źródło
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:
Można tego po prostu uniknąć, sprawdzając, czy zmienna nie ma wartości null:
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ć):
Typy wartości (możesz po prostu zignorować te):
źródło
Innym przypadkiem, w którym
NullReferenceExceptions
może się zdarzyć, jest (nieprawidłowe) użycieas
operatora :W tym przypadku,
Book
iCar
to niezgodne rodzajów;Car
nie można przekształcić / rzutowany naBook
. Gdy rzutowanie nie powiedzie się,as
powracanull
. Używaniemybook
póź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:
Jeśli nie masz pewności co do typu, ale chcesz spróbować użyć go jako określonego typu, użyj
as
:źródło
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:
Błąd wyjątku to:
źródło
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żyteczny
Debugger.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
myString
wartość zero. Można to zweryfikować, patrząc na okno obserwacyjne lub uruchamiając wyrażenia w oknie natychmiastowym .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
str1
to null, czy jeślistr2
było null.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ć .
źródło
Simon Mourier podał ten przykład :
gdzie unboxing konwersji (cast) z
object
(lub z jednej z klasSystem.ValueType
lubSystem.Enum
czy od typu interfejsu) do typu wartości (inne niżNullable<>
) sam w sobie dajeNullReferenceException
.W drugim kierunku, boks konwersji z
Nullable<>
, który maHasValue
równyfalse
z typu odniesienia, można podaćnull
odniesienie, który później może prowadzić doNullReferenceException
. Klasyczny przykład to:Czasami boks dzieje się w inny sposób. Na przykład za pomocą tej niestandardowej metody rozszerzenia:
następujący kod będzie problematyczny:
Te przypadki powstają z powodu specjalnych zasad, które środowisko wykonawcze stosuje podczas tworzenia boksu
Nullable<>
.źródło
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 ()
Ze względu na kompletność klasy DataContext
i klasa jednostki kontaktowej. Czasami klasy jednostek są częściowymi klasami, dzięki czemu można je również rozszerzyć na inne pliki.
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 ()
źródło
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
HttpContext
któ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.
źródło
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.
źródło
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ąć
NullReferenceException
przypadków, które są wynikiem naruszenia zestawu ograniczeń. Na przykład, jeśli użyjesz właściwości obiektuX
w klasie, a później spróbujesz wywołać jedną z jej metod iX
ma ona wartość zerową, spowoduje toNullReferenceException
: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:
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 .
źródło
A
NullReferenceException
jest 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:
Gdy uzyskano dostęp do metody ciągu pustego:
Gdy uzyskano dostęp do właściwości pustego obiektu:
źródło
String.Empty.ToLower()
nie zgłosi wyjątku zerowego odniesienia. Reprezentuje rzeczywisty ciąg, choć pusty (tj""
.). Ponieważ ma to obiekt do wywołaniaToLower()
, nie ma sensu umieszczać w nim wyjątku o wartości zerowej.TL; DR: Spróbuj użyć
Html.Partial
zamiastRenderpage
Otrzymywałem,
Object reference not set to an instance of an object
gdy próbowałem renderować widok w widoku, wysyłając mu model, taki jak ten:Debugowanie pokazało, że model był pusty w MyOtherView. Aż zmieniłem to na:
I zadziałało.
Ponadto powodem, dla którego nie musiałem
Html.Partial
zaczynać, było to, że Visual Studio czasami rzuca wyglądające na błędne linie, pod którymiHtml.Partial
znajduje się w inaczej skonstruowanejforeach
pętli, mimo że tak naprawdę nie jest to błąd:Ale udało mi się uruchomić aplikację bez problemów z tym „błędem”. Mogłem pozbyć się błędu, zmieniając strukturę
foreach
pętli, aby wyglądała następująco:Chociaż mam wrażenie, że było tak, ponieważ Visual Studio źle odczytał znaki handlowe i nawiasy klamrowe.
źródło
Html.Partial
, nie@Html.Partial
Null
), więc wiedziałem, że błąd dotyczy sposobu wysyłania modelu.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ć
ArgumentNullException
wyjątek, który oczywiście został stworzony w tym właśnie celu.Konstruktor
ArgumentNullException
parzystego przyjmuje nazwę parametru i komunikat jako argumenty, abyś mógł powiedzieć deweloperowi, na czym polega problem.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:
W ten sposób i włączenie PostSharp do procesu kompilacji
obj
będzie sprawdzane pod kątem zerowości w czasie wykonywania. Zobacz: Kontrola zerowa PostSharpRozwią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>
: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<T>
jest niejawnie przesyłany do iz miejsca,T
dzięki czemu można go używać niemal wszędzie tam, gdzie jest to potrzebne. Na przykład możesz przekazaćPerson
obiekt do metody, która przyjmujeNotNull<Person>
:Jak widać powyżej, podobnie jak w przypadku wartości zerowej, można uzyskać dostęp do wartości bazowej za pośrednictwem
Value
właściwości. Alternatywnie możesz użyć jawnej lub niejawnej rzutowania, możesz zobaczyć przykład z wartością zwracaną poniżej:Możesz też użyć go, gdy metoda właśnie powraca
T
(w tym przypadkuPerson
), wykonując rzut. Na przykład poniższy kod byłby podobny do powyższego: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:A oto przykład, jak można go użyć:
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
null
zwraca całe wyrażenienull
.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:
Wyobraź sobie, że
country
jest to obiekt typu,Country
który ma właściwość o nazwieState
i tak dalej. Jeślicountry
,State
,County
, lubCity
jestnull
wtedyaddress will be
zerowy. Therefore you only have to check whether
adresis
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 typemint?
.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)
.źródło
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,
NullReference
a nawet (częściej),KeyNotFoundException
gdy 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
NullReferenceException
jest rzucany przez aunsafe
, możesz spojrzeć na zmienne wskaźnika i sprawdzić,IntPtr.Zero
czy 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)
źródło
null
w jaki sposób?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
jest równa:
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
źródło
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.
Teraz uzyskujesz dostęp do tego prop1 w innej klasie, tak jak poniżej:
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).
źródło
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.
Teraz rozważ inną klasę, w której próbujesz odzyskać pełne imię i nazwisko ucznia.
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.
źródło
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:
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.
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:
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”);
źródło
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:
Następnie przejdź do skryptu i wpisz
rb = GetComponent<Rigidbody>();
Ten wiersz kodu działa najlepiej pod twoim
Start()
lubAwake()
funkcjami.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!
źródło
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:
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)
źródło
Jest to w zasadzie wyjątek odniesienia Null . Jak Microsoft Zjednoczonych byli
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.
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).
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:
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.
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.
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.
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.
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!
źródło
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.
źródło