Unity中如何抛出带UnityEngine.Object上下文的异常?
Great question! I’ve run into this exact scenario before, and there’s a clean way to achieve what you’re asking—combining C# exception behavior (terminating execution, catchability) with Unity’s console context highlighting, without duplicate logs.
Here’s a step-by-step solution:
1. Create a Custom Exception Class
First, define a custom exception that stores your Unity object context. This lets you carry the context alongside the exception message and inner exceptions:
using System; using UnityEngine; public class UnityContextException : Exception { // Store the Unity object to highlight in the Hierarchy public Object Context { get; } // Basic constructor public UnityContextException(string message, Object context) : base(message) { Context = context; } // Constructor with inner exception support public UnityContextException(string message, Exception innerException, Object context) : base(message, innerException) { Context = context; } }
2. Build a Global Exception Handler
Next, create a script that intercepts Unity’s log output to avoid duplicate entries, while ensuring your context-rich error gets displayed properly. Attach this to a persistent GameObject (like a GameManager set to DontDestroyOnLoad) so it works across all scenes:
using UnityEngine; public class ExceptionContextLogger : MonoBehaviour { // Flag to track when we've thrown our custom exception private static bool _isContextExceptionPending; private void OnEnable() { // Subscribe to Unity's log callback Application.logMessageReceivedThreaded += HandleLogEvent; } private void OnDisable() { // Unsubscribe to prevent memory leaks Application.logMessageReceivedThreaded -= HandleLogEvent; } private void HandleLogEvent(string logString, string stackTrace, LogType logType, ref bool cancel) { // Cancel the default exception log if it's our custom context exception if (logType == LogType.Exception && _isContextExceptionPending && logString.Contains(nameof(UnityContextException))) { cancel = true; _isContextExceptionPending = false; // Reset the flag } } // Static method to throw your context-aware exception public static void Throw(string message, Object context) { // Print the error with Unity context (enables Hierarchy highlighting) Debug.LogError(message, context); // Flag that we're about to throw our custom exception _isContextExceptionPending = true; // Throw the exception to halt execution throw new UnityContextException(message, context); } // Overload for exceptions with inner causes public static void Throw(string message, Exception innerException, Object context) { Debug.LogError($"{message}\nInner Exception: {innerException.Message}", context); _isContextExceptionPending = true; throw new UnityContextException(message, innerException, context); } }
3. Use the Context-Aware Throw
Now you can throw exceptions that behave like regular C# exceptions, but add Unity’s console highlighting, with just one line of code:
// Example: Throw an error linked to a GameObject ExceptionContextLogger.Throw("Failed to initialize player controller!", playerControllerGameObject);
Key Benefits:
- No duplicate logs: The handler cancels Unity’s default exception output, leaving only your context-rich
Debug.LogErrorentry. - Hierarchy highlighting: Clicking the console error will automatically select the linked Unity object in the Hierarchy.
- Full exception behavior: The exception will terminate execution, can be caught with
try/catch, and preserves stack trace information.
Catching the Custom Exception
You can catch this exception just like any other C# exception, and even access the stored context:
try { ExceptionContextLogger.Throw("Test error", someGameObject); } catch (UnityContextException ex) { Debug.LogWarning($"Caught error: {ex.Message}\nAffected Object: {ex.Context.name}"); }
内容的提问来源于stack exchange,提问作者E. Zacarias

