Ponieważ wielu użytkowników napotyka NullReferenceException: Object reference not set to an instance of an object
błąd w Unity, pomyślałem, że dobrym pomysłem byłoby zebranie z wielu źródeł wyjaśnień i sposobów naprawienia tego błędu.
Objawy
W konsoli pojawia się poniższy błąd, co to znaczy i jak go naprawić?
NullReferenceException: Odwołanie do obiektu nie jest ustawione na instancję obiektu
unity
exceptions
Hel
źródło
źródło
Odpowiedzi:
Typ wartości a typ odniesienia
W wielu językach programowania zmienne mają tak zwany „typ danych”. Dwa podstawowe typy danych to typy wartości (int, float, bool, char, struct, ...) i typ referencyjny (instancja klas). Podczas gdy typy wartości zawierają samą wartość , odwołania zawierają adres pamięci wskazujący na część pamięci przydzieloną na zbiór wartości (podobny do C / C ++).
Na przykład
Vector3
jest typem wartości (strukturą zawierającą współrzędne i niektóre funkcje), podczas gdy komponenty dołączone do GameObject (w tym dziedziczące skrypty niestandardoweMonoBehaviour
) są typem referencyjnym.Kiedy mogę otrzymać wyjątek NullReferenceException?
NullReferenceException
są rzucane, gdy próbujesz uzyskać dostęp do zmiennej referencyjnej, która nie odwołuje się do żadnego obiektu, dlatego jest pusta (adres pamięci wskazuje 0).Niektóre typowe miejsca
NullReferenceException
zostaną podniesione:Manipulowanie GameObject / Component, który nie został określony w inspektorze
Pobieranie komponentu, który nie jest dołączony do GameObject, a następnie próba manipulowania nim:
Dostęp do GameObject, który nie istnieje:
Uwaga: Należy zachować ostrożność,
GameObject.Find
,GameObject.FindWithTag
,GameObject.FindObjectOfType
tylko wrócić gameObjects które są włączone w hierarchii, gdy funkcja jest wywoływana.Próba użycia wyniku zwracającego getter
null
:Dostęp do elementu niezainicjowanej tablicy
Mniej powszechne, ale irytujące, jeśli nie wiesz o delegatach C #:
Jak naprawić ?
Jeśli zrozumiałeś poprzednie paragrafy, wiesz, jak naprawić błąd: upewnij się, że twoja zmienna odwołuje się (wskazuje) na instancję klasy (lub zawiera co najmniej jedną funkcję dla delegatów).
Łatwiej powiedzieć niż zrobić? W rzeczy samej. Oto kilka wskazówek, jak uniknąć i zidentyfikować problem.
„Brudny” sposób: metoda try & catch:
„Czystszy” sposób (IMHO): czek
W obliczu błędu, którego nie można rozwiązać, zawsze dobrze jest znaleźć przyczynę problemu. Jeśli jesteś „leniwy” (lub jeśli problem można łatwo rozwiązać), użyj przycisku,
Debug.Log
aby wyświetlić na konsoli informacje, które pomogą ci zidentyfikować przyczynę problemu. Bardziej złożonym sposobem jest użycie punktów przerwania i debuggera IDE.Użycie
Debug.Log
jest na przykład przydatne do określenia, która funkcja jest wywoływana jako pierwsza. Zwłaszcza jeśli masz funkcję odpowiedzialną za inicjowanie pól. Ale nie zapomnij usunąć tych,Debug.Log
aby uniknąć zaśmiecania konsoli (i ze względu na wydajność).Kolejna rada, nie wahaj się „wyciąć” wywołania funkcji i dodaj,
Debug.Log
aby sprawdzić.Zamiast :
Zrób to, aby sprawdzić, czy ustawione są wszystkie odwołania:
Nawet lepiej :
Źródła:
źródło
try/catch
. Błąd mówi ci wiele o twoim problemie, a zanim początkujący zaczną wszędzie sprawdzać wartości zerowe, głównym problemem jest inspektor, ponieważ zapominasz odwołać się do jakiegoś obiektu (przeciągnij obiekt na skrypt). Widziałem dużo kodu ztry/catch
zerowymi kontrolami w miejscach, w których jest to całkowicie niepotrzebne. Debugowanie i praca z takim kodem to „ból w **”. Początkujący uczą się o przypadkach użycia tych czeków i dopiero wtedy ich używają.else
. PosiadanieNullReferenceException
nie zawsze jest oczywiste, aleNo Rigidbody component attached to the gameObject
bezpośrednio wyjaśnia, co jest nie tak. Zgadzam się, że samaif( obj != null )
wiadomość „bez” po prostu „ukrywa” problem i możesz mieć działający projekt, ale nie robić tego, czego byś się nie spodziewał, nie wiedząc, dlaczego.Chociaż możemy łatwo sprawdzić, czy nie próbujemy uzyskać dostępu do pustego odwołania, nie zawsze jest to odpowiednie rozwiązanie. Wiele razy, w programowaniu Unity, nasz problem może wynikać z faktu, że referencja nie powinna być zerowa. W niektórych sytuacjach po prostu zignorowanie pustych referencji może uszkodzić nasz kod.
Na przykład może to być odniesienie do naszego kontrolera wejściowego. Wspaniale jest, że gra nie ulega awarii z powodu wyjątku zerowego odniesienia, ale musimy dowiedzieć się, dlaczego nie ma kontrolera wejściowego i naprawić ten problem. Bez tego mamy grę, która nie może ulec awarii, ale nie może też brać udziału.
Poniżej wymienię możliwe przyczyny i rozwiązania, które napotykam w innych pytaniach.
Czy próbujesz uzyskać dostęp do klasy „manager”?
Jeśli próbujesz uzyskać dostęp do klasy, która działa jak „menedżer” (to znaczy, klasy, która powinna mieć zawsze tylko jedną instancję na raz), możesz lepiej zastosować metodę Singleton . Do klasy Singleton można idealnie uzyskać dostęp z dowolnego miejsca, bezpośrednio, zachowując
public static
odniesienie do siebie. W ten sposób Singleton może zawierać odwołanie do aktywnej instancji, które byłoby dostępne bez problemu z ustawieniem rzeczywistego odwołania za każdym razem.Czy odwołujesz się do instancji swojego obiektu?
Zazwyczaj wystarczy zaznaczyć oznaczenie jako
public
, abyśmy mogli ustawić odwołanie do instancji za pośrednictwem inspektora. Zawsze sprawdź, czy nie ustawić odwołanie do instancji, przez inspektora, gdyż nie jest rzadkością przegapić ten krok.Czy tworzysz instancję?
Jeśli konfigurujemy nasz obiekt w kodzie, ważne jest, aby utworzyć jego instancję . Można to zrobić za pomocą
new
słowa kluczowego i metod konstruktora. Rozważ na przykład:Stworzyliśmy odniesienie do
GameObject
, ale nic nie wskazuje. Uzyskanie dostępu do tego odwołania w obecnej postaci spowoduje wyjątek zerowy . Zanim odwołamy się do naszegoGameObject
wystąpienia, możemy wywołać domyślną metodę konstruktora w następujący sposób:Samouczek Unity dotyczący klas wyjaśnia praktykę tworzenia i używania konstruktorów.
Czy używasz
GetComponent<t>()
metody przy założeniu, że składnik istnieje?Po pierwsze, upewnij się, że zawsze wywołujemy
GetComponent<t>()
przed wywołaniem metod z instancji komponentu.Z powodów, dla których nie warto wchodzić, możemy założyć, że nasz lokalny obiekt gry zawiera określony komponent i spróbować uzyskać do niego dostęp
GetComponent<t>()
. Jeśli lokalny obiekt gry nie zawiera tego konkretnego komponentu, zwrócimynull
wartość.Możesz łatwo sprawdzić, czy zwracana jest wartość
null
, przed uzyskaniem do niej dostępu. Jeśli jednak obiekt gry powinien mieć wymagany komponent, lepiej upewnić się, że ma przynajmniej domyślną wersję tego komponentu. Możemy oznaczyćMonoBehaviour
jako,[RequireComponent(typeof(t))]
aby upewnić się, że zawsze mamy ten typ komponentu.Oto przykład
MonoBehaviour
obiektu gry, który zawsze powinien zawieraćRigidbody
. Jeśli skrypt zostanie dodany do obiektu gry, który nie zawiera aRigidbody
,Rigidbody
zostanie utworzony domyślny .Czy próbowałeś odbudować swój projekt?
W niektórych przypadkach Unity może powodować problemy, próbując odwołać się do buforowanej wersji obiektu gry. Zgodnie z odwiecznym rozwiązaniem „wyłącz i włącz ponownie”, spróbuj usunąć folder Library i ponownie otwórz Unity. Unity będzie zmuszony przebudować twój projekt. Może to rozwiązać niektóre bardzo szczególne przypadki tego problemu i powinno wskazywać na problemy, które nie pojawią się w ostatecznej wersji.
źródło
Widzę, że istnieje akceptowana odpowiedź. Ale jest lepsza odpowiedź lub sugestia dotycząca obsługi
NullReferenceException
. Jeśli możesz powiązać programowanie w języku Java, takim jak ja, możesz zapobiec wysyłaniu błędu zerowego, używająctry-catch
bloku. Wypróbuj sam! ;-)Jeśli używasz w C #, sprawdź, czy masz
using System;
na górze pliku skryptu. Jeśli nie, dodaj go. Teraz możesz używać różnego rodzajuException
klas, próbując złapać wiersz kodu.Jeśli używasz UnityScript, użyj
import System;
Oto przykład:
Należy również pamiętać, można złapać także inne wyjątki takie jak
MissingReferenceException
,MissingComponentException
,IndexOutOfRangeException
, lub innych klas wyjątków tak długo, jak tousing System
w skrypcie.To wszystko.
źródło