Здесь уже есть несколько ответов, но вот ответ, который учитывает 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
исключение?