Здесь уже есть несколько ответов, но вот ответ, который учитывает Unity3D (ответ очень специфичен для Unity3D, я сделал бы большую часть этого совсем по-другому в большинстве контекстов):
В общем, Unity3D не использует исключения традиционно. Если вы выбросите исключение в Unity3D, это не будет похоже на обычное приложение .NET, а именно, оно не остановит программу, в большинстве случаев вы можете настроить редактор на паузу. Это просто будет зарегистрировано. Это может легко перевести игру в недопустимое состояние и создать каскадный эффект, который затруднит отслеживание ошибок. Так что я бы сказал, что в случае с Unity разрешение Addбросить исключение является особенно нежелательным вариантом.
Но при рассмотрении скорости исключений в некоторых случаях не бывает преждевременной оптимизации из-за того, как Mono работает в Unity на некоторых платформах. На самом деле Unity3D на iOS поддерживает некоторые дополнительные оптимизации сценариев, и отключенные исключения * являются побочным эффектом одного из них. Это действительно то, что нужно учитывать, потому что эти оптимизации оказались очень ценными для многих пользователей, демонстрируя реалистичный пример рассмотрения вопроса об ограничении использования исключений в Unity3D. (* управляемые исключения из движка, а не ваш код)
Я бы сказал, что в Unity вы можете использовать более специализированный подход. По иронии судьбы, очень недооцененный ответ на момент написания этой статьи показывает, как я мог бы реализовать что-то подобное именно в контексте Unity3D (в других местах что-то подобное действительно недопустимо, и даже в Unity это довольно не элегантно).
Другой подход, который я рассмотрю, на самом деле не указывает на ошибку в том, что касается вызывающего, а скорее использует Debug.LogXXфункции. Таким образом, вы получаете то же поведение, что и создание необработанного исключения (из-за того, как Unity3D обрабатывает их), не рискуя поместить что-то в странное состояние. Также подумайте, действительно ли это ошибка (Попытка загрузить один и тот же материал дважды обязательно ошибка в вашем случае? Или это может быть Debug.LogWarningболее подходящим случаем ).
А что касается использования таких вещей, как Debug.LogXXфункции, а не исключения, вам все равно нужно учитывать, что происходит, когда исключение будет выдано из чего-то, что возвращает значение (например, GetMaterial). Я склоняюсь к этому, передавая ноль вместе с записью ошибки ( опять же, только в Unity ). Затем я использую нулевые проверки в моем MonoBehaviors, чтобы гарантировать, что любая зависимость, например материал, не является нулевым значением, и отключаю MonoBehavior, если это так. Примером простого поведения, которое требует нескольких зависимостей, является что-то вроде этого:
public void Awake()
{
_inputParameters = GetComponent<VehicleInputParameters>();
_rigidbody = GetComponent<Rigidbody>();
_rigidbodyTransform = _rigidbody.transform;
_raycastStrategySelector = GetComponent<RaycastStrategySelectionBehavior>();
_trackParameters =
SceneManager.InstanceOf.CurrentSceneData.GetValue<TrackParameters>();
this.DisableIfNull(() => _rigidbody);
this.DisableIfNull(() => _raycastStrategySelector);
this.DisableIfNull(() => _inputParameters);
this.DisableIfNull(() => _trackParameters);
}
SceneData.GetValue<>похож на ваш пример в том, что он вызывает функцию в словаре, которая выдает исключение. Но вместо того, чтобы вызвать исключение, оно использует Debug.LogErrorтрассировку стека, как обычное исключение, и возвращает ноль. Следующие проверки * отключат поведение, а не позволят ему продолжать существовать в недопустимом состоянии.
* проверки выглядят так из-за небольшого помощника, который я использую, который печатает отформатированное сообщение, когда он отключает игровой объект **. Простые проверки нуля с ifработой здесь (** проверки помощника компилируются только в сборках отладки (например, утверждений). Использование лямбда-выражений и таких выражений в Unity может повлиять на производительность)
_Materials.Addисключение?