Jest tu już kilka odpowiedzi, ale oto odpowiedź, która uwzględnia Unity3D (odpowiedź jest bardzo specyficzna dla Unity3D, większość z nich zrobiłbym inaczej w większości kontekstów):
Ogólnie rzecz biorąc, Unity3D nie wykorzystuje tradycyjnie wyjątków. Jeśli rzucisz wyjątek w Unity3D, nie będzie to tak jak w przeciętnej aplikacji .NET, a mianowicie nie zatrzyma programu, t większość możesz skonfigurować edytor do pauzy. Zostanie tylko zalogowany. Może to łatwo doprowadzić grę do nieprawidłowego stanu i stworzyć efekt kaskady, który utrudnia wyśledzenie błędów. Tak więc powiedziałbym w przypadku Unity, pozwolenie na Add
rzucenie wyjątku jest szczególnie niepożądaną opcją.
Ale badanie szybkości wyjątków nie jest w niektórych przypadkach przypadkiem przedwczesnej optymalizacji z powodu tego, jak Mono działa w Unity na niektórych platformach. W rzeczywistości Unity3D na iOS obsługuje niektóre zaawansowane optymalizacje skryptów, a wyłączone wyjątki * to efekt uboczny jednego z nich. Jest to naprawdę coś do rozważenia, ponieważ te optymalizacje okazały się bardzo cenne dla wielu użytkowników, co pokazuje realistyczny przypadek rozważenia ograniczenia stosowania wyjątków w Unity3D. (* zarządzane wyjątki od silnika, a nie kod)
Powiedziałbym, że w Unity możesz chcieć przyjąć bardziej wyspecjalizowane podejście. Jak na ironię, bardzo odrzucona odpowiedź w momencie pisania tego , pokazuje jeden sposób, w jaki mógłbym wdrożyć coś takiego właśnie w kontekście Unity3D (gdzie indziej coś takiego jest naprawdę nie do przyjęcia, a nawet w Unity jest dość nieeleganckie).
Innym podejściem, które rozważam, w rzeczywistości nie jest wskazanie błędu w stosunku do dzwoniącego, ale raczej użycie Debug.LogXX
funkcji. W ten sposób otrzymujesz to samo zachowanie, co zgłaszanie nieobsługiwanego wyjątku (z powodu sposobu, w jaki obsługuje je Unity3D) bez ryzyka narażenia czegoś w dziwnym stanie na linii. Zastanów się także, czy to naprawdę jest błąd (czy próba załadowania tego samego materiału dwa razy niekoniecznie oznacza błąd w twoim przypadku? A może to przypadek, w którym Debug.LogWarning
jest to bardziej odpowiednie).
A jeśli chodzi o korzystanie z Debug.LogXX
funkcji takich jak funkcje zamiast wyjątków, nadal musisz zastanowić się, co się stanie, gdy wyjątek zostanie zgłoszony z czegoś, co zwraca wartość (np. GetMaterial). Podchodzę do tego, przekazując zero i rejestrując błąd ( znowu tylko w Unity ). Następnie używam kontroli zerowej w moich MonoBehaviors, aby upewnić się, że jakakolwiek zależność, taka jak materiał, nie jest wartością zerową, i wyłączam MonoBehavior, jeśli jest. Przykładem prostego zachowania wymagającego kilku zależności jest coś takiego:
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<>
jest podobny do twojego przykładu, ponieważ wywołuje funkcję w słowniku, która zgłasza wyjątek. Ale zamiast zgłaszania wyjątku używa tego, Debug.LogError
co daje ślad stosu, tak jak normalny wyjątek, i zwraca wartość null. Kontrole, które następują *, wyłączą to zachowanie, zamiast pozwolić, aby istniało nadal w nieprawidłowym stanie.
* czeki wyglądają tak z powodu małego pomocnika, którego używam, który drukuje sformatowaną wiadomość, gdy wyłącza obiekt gry **. Proste sprawdzanie wartości zerowej z if
pracą tutaj (** czeki pomocnika są kompilowane tylko w kompilacjach Debugowania (takich jak aserts). Używanie lambd i takich wyrażeń w Unity może mieć negatywny wpływ na wydajność)
_Materials.Add
zgłasza wyjątek?