Поскольку многие пользователи сталкиваются с NullReferenceException: Object reference not set to an instance of an object
ошибкой в Unity, я подумал, что было бы неплохо собрать из нескольких источников некоторые объяснения и способы исправления этой ошибки.
симптомы
Я получаю сообщение об ошибке ниже, появляющееся в моей консоли, что это значит и как я могу это исправить?
NullReferenceException: ссылка на объект не установлена на экземпляр объекта
unity
exceptions
Hellium
источник
источник
Ответы:
Тип значения против Тип ссылки
Во многих языках программирования переменные имеют так называемый «тип данных». Двумя основными типами данных являются типы значений (int, float, bool, char, struct, ...) и ссылочный тип (экземпляр классов). В то время как типы значений содержат само значение , ссылки содержат адрес памяти, указывающий на часть памяти, выделенную для хранения набора значений (аналогично C / C ++).
Например,
Vector3
это тип значения (структура, содержащая координаты и некоторые функции), в то время как компоненты, прикрепленные к вашему GameObject (включая ваши собственные сценарии, наследуемые отMonoBehaviour
), являются ссылочным типом.Когда я могу получить исключение NullReferenceException?
NullReferenceException
сбрасываются, когда вы пытаетесь получить доступ к ссылочной переменной, которая не ссылается на какой-либо объект, поэтому она имеет значение null (адрес памяти указывает на 0).Некоторые общие места
NullReferenceException
будут подняты:Управление GameObject / Component, который не был указан в инспекторе
Извлечение компонента, который не присоединен к GameObject, а затем попытка манипулировать им:
Доступ к GameObject, который не существует:
Примечание: Будьте осторожны,
GameObject.Find
,GameObject.FindWithTag
,GameObject.FindObjectOfType
возвращать только геймобжекты, которые включены в иерархии , когда функция вызывается.Попытка использовать результат получателя, который возвращает
null
:Доступ к элементу неинициализированного массива
Менее распространенный, но раздражающий, если вы не знаете об делегатах C #:
Как исправить ?
Если вы поняли предыдущие параграфы, вы знаете, как исправить ошибку: убедитесь, что ваша переменная ссылается (указывает на) на экземпляр класса (или содержит хотя бы одну функцию для делегатов).
Проще сказать, чем сделать? Да, в самом деле. Вот несколько советов, чтобы избежать и определить проблему.
«Грязный» способ: метод try & catch:
«Чистый» способ (ИМХО): чек
Когда вы сталкиваетесь с ошибкой, которую вы не можете решить, всегда полезно найти причину проблемы. Если вы «ленивы» (или если проблему легко решить), используйте
Debug.Log
для отображения на консоли информацию, которая поможет вам определить причину проблемы. Более сложным способом является использование точек останова и отладчика вашей IDE.Использование
Debug.Log
весьма полезно для определения, например, какая функция вызывается первой. Особенно, если у вас есть функция, отвечающая за инициализацию полей. Но не забудьте удалить их,Debug.Log
чтобы не загромождать вашу консоль (и по соображениям производительности).Еще один совет, не стесняйтесь «обрезать» свои вызовы функций и добавить,
Debug.Log
чтобы сделать некоторые проверки.Вместо :
Сделайте это, чтобы проверить, установлены ли все ссылки:
Даже лучше :
Источники:
источник
try/catch
. Ошибка многое говорит вам о вашей проблеме, и прежде чем новички начнут везде ставить нулевые проверки, ваша главная проблема в инспекторе, поскольку вы забываете ссылаться на некоторый объект (перетащите объект в скрипт). Я видел много кода сtry/catch
пустыми проверками в местах, где это совершенно не нужно. Отладка и работа с подобным кодом - это «боль в а **». Новички узнают о случаях использования этих проверок и только затем используют их.else
. НаличиеNullReferenceException
не всегдаNo Rigidbody component attached to the gameObject
говорит само за себя, а прямо объясняет, что не так. Я согласен, что простоif( obj != null )
отсутствие сообщения просто «скрывает» проблему, и вы можете иметь работающий проект, но не делать то, что ожидаете, не зная, почему.Хотя мы можем легко выполнить проверку, чтобы убедиться, что мы не пытаемся получить доступ к нулевой ссылке, это не всегда подходящее решение. Во многих случаях в программировании Unity наша проблема может быть связана с тем, что ссылка не должна быть нулевой. В некоторых ситуациях простое игнорирование нулевых ссылок может нарушить наш код.
Например, это может быть ссылка на наш контроллер ввода. Здорово, что игра не вылетает из-за исключения с нулевой ссылкой, но нам нужно выяснить, почему нет контроллера ввода, и исправить эту проблему. Без этого у нас есть игра, которая может не рухнуть, но также не может принять ввод.
Ниже я перечислю возможные причины и решения, так как сталкиваюсь с ними в других вопросах.
Вы пытаетесь получить доступ к классу "менеджер"?
Если вы пытаетесь получить доступ к классу, который действует как «менеджер» (то есть, к классу, который должен иметь только один экземпляр за раз), вам лучше использовать подход Singleton . К классу Singleton в идеале можно обращаться откуда угодно, напрямую, сохраняя
public static
ссылку на себя. Таким образом, Singleton может содержать ссылку на активный экземпляр, который будет доступен без необходимости каждый раз устанавливать фактическую ссылку.Вы ссылаетесь на экземпляр вашего объекта?
Обычно просто помечают ссылку как
public
, чтобы мы могли установить ссылку на экземпляр через инспектор. Всегда убедитесь , что вы бы установить ссылку на экземпляр, с помощью инспектора, так как это не редкость , чтобы пропустить этот шаг.Вы инстанцируете свой экземпляр?
Если мы настраиваем наш объект в коде, важно убедиться, что мы создаем его экземпляр . Это может быть выполнено с использованием
new
ключевого слова и методов конструктора. Например, рассмотрим следующее:Мы создали ссылку на a
GameObject
, но она ни на что не указывает. Доступ к этой ссылке как есть приведет к исключению пустой ссылки . Прежде чем ссылаться на нашGameObject
экземпляр, мы можем вызвать метод конструктора по умолчанию следующим образом:Учебник Unity по классам объясняет практику создания и использования конструкторов.
Используете ли вы
GetComponent<t>()
метод с предположением, что компонент существует?Во-первых, убедитесь, что мы всегда вызываем
GetComponent<t>()
до вызова методов из экземпляра компонента.По причинам, не заслуживающим внимания, мы можем предположить, что наш локальный игровой объект содержит определенный компонент, и попытаться получить к нему доступ
GetComponent<t>()
. Если локальный игровой объект не содержит этот конкретный компонент, мы вернемnull
значение.Вы можете легко проверить, является ли возвращаемое значение
null
, до доступа к нему. Однако, если ваш игровой объект должен иметь обязательный компонент, может быть лучше убедиться, что он по крайней мере имеет версию этого компонента по умолчанию . Мы можем пометитьMonoBehaviour
как,[RequireComponent(typeof(t))]
чтобы гарантировать, что у нас всегда есть этот тип компонента.Вот пример
MonoBehaviour
для игрового объекта, который всегда должен содержатьRigidbody
. Если сценарий добавляется к игровому объекту, который не содержитRigidbody
, создается значение по умолчаниюRigidbody
.Вы пытались пересобрать свой проект?
В некоторых случаях Unity может вызвать проблемы, пытаясь ссылаться на кэшированную версию игрового объекта. В соответствии со старым решением «выключите и снова включите», попробуйте удалить папку библиотеки и заново открыть Unity. Unity будет вынуждена пересобрать ваш проект. Это может решить некоторые очень специфические случаи этой проблемы и должно указывать на проблемы, которые не возникнут в окончательной сборке.
источник
Я вижу, что есть принятый ответ. Но есть лучший ответ или предложение для вас для обработки
NullReferenceException
. Если вы можете связать программирование на языке Java, как я, вы можете предотвратить отправку нулевой ошибки, используяtry-catch
блок. Попробуйте сами! ;-)Если вы используете в C #, проверьте, есть ли у вас
using System;
в верхней части файла сценария. Если нет, добавьте это. Теперь вы можете использовать все видыException
классов, пытаясь поймать строку кода.Если вы используете UnityScript, используйте
import System;
Вот пример:
Также помните, что вы можете поймать и другие исключения , такие как
MissingReferenceException
,MissingComponentException
,IndexOutOfRangeException
, или любые другие классы исключений , как если вы включитеusing System
в свой сценарий.Это все.
источник