Самая первая мысль об этом: Не делайте этого ^^
При этом есть одна проблема: вы изменяете трассировку стека вызова.Передав нулевую проверку статическому классу, когда вы видите ошибку в консоли, которую вы не можете любить, прежде чем непосредственно увидеть, где она была выброшена / записана, сразу перейдите к соответствующей строке кода, дважды щелкнув по ней и не может (это легко) выделите соответствующий объект «контекст» в иерархии.
Таким образом, я бы всегда держал чеки как можно ближе к фактическому использованию и скорее делал бы это как
if(!offHandEquipLocation) Debug.LogError($"{nameof(offHandEquipLocation)} is not referenced!", this);
Весь смысл Debug.Log
облегчает вашу жизнь при отладке;) Использование вышеуказанного подхода дает гораздо больше преимуществ, чем тот факт, что при использовании этого подхода вам не нужно вводить Debug.LogError($"{nameof(offHandEquipLocation)} is not referenced!", this);
несколько раз.
Как и другие, я уже упоминал причину, по которой это не так.Работает так, как вы ожидаете, это пользовательское == null
поведение Unity для типа Object
, из которого большинство встроенных типов, в частности GameObject
, ScriptableObject
и Component
наследовать.
Даже если Object
"может показаться" или, лучше сказать, возвращает значение , равное значению null
Unity фактически сохраняетнекоторая метаинформация в справочнике для создания пользовательских исключений (MissingReferenceException
, MissingComponentException
, UnassignedReferenceException
), которые более понятны, чем простые NullReferenceException
(как вы также можете увидеть здесь ),Следовательно, на самом деле это не null
в базовом типе object
.
Как только вы преобразуете его в object
, пользовательское поведение == null
исчезнет, но базовое object
все еще существует и, следовательно,вы получаете field == null
→ false
Однако решение может заключаться в создании простой перегрузки с использованием оператора bool
для Object
.Это заменяет проверку null
и означает что-то вроде This object is referenced, exists, and was not destroyed yet.
.И продолжайте использовать == null
для всего остального
public static void RequireField(string name, object field)
{
if (field == null) Debug.LogError($"{name} field is unset");
}
public static void RequireField(string name, Object field)
{
if (!field) Debug.LogError($"{name} field is unset");
}
Теперь вы можете использовать оба.В качестве небольшого примечания: я бы не использовал глагол string
для первого параметра, но вместо этого всегда передавал бы его с использованием nameof
, чтобы сделать его более безопасным для переименований
var GameObject someObject;
var string someString;
Validation.validate(nameof(someObject), someObject);
Validation.validate(nameof(someString), someString);
Небольшой sidenoteотносительно вашего аргумента для использования этого, например, string
в целом:
Как только это поле будет public
или [SerializedField]
в Инспекторе для любого Component
(MonoBehaviour
) или ScriptableObject
он всегда инициализируется самим инспектором Unity со значением по умолчанию.Следовательно, нулевая проверка любого из, например,
public int intValue;
[SerializeField] private string stringValue;
public Vector3 someVector;
public int[] intArray;
...
, является избыточной, поскольку ни один из них никогда не будет null
.Это относится и к любому сериализуемому типу, так что даже если у вас есть собственный класс
[Serializable]
public class Example
{
public string aField;
}
, а затем вы используете в своем поведении сериализованное поле, например,
public List<Example> example;
, этот также никогда не будетбыть null
.
Кстати, как уже упоминалось, Validation
не должно наследоваться от MonoBehaviour
, а должно быть
public static class Validation
{
// only static members
...
}