Попробуйте перехватить блок кода, который не выполняется в Unity

#c# #visual-studio #unity3d

Вопрос:

У меня есть предложение try-catch в многопользовательском проекте для проверки состояния соединения (через UDP) в Unity. Он получает обратный вызов от сервера в блоке кода try, а блок кода catch предназначен для получения исключения в случае внезапного прерывания соединения. Моя проблема в том, что блок catch не выполняет код, который я использую для информирования пользователя о том, что соединение с сервером было потеряно. Кажется, что он выполняет код только относительно исключения (например, Отладка.Error(e)).

 //Callback from server connection
        private void ConnectCallback(IAsyncResult _result) {
            try {
                //Ends connection
                socket.EndConnect(_result);
            } catch (Exception e) {
                
               //These three lines are the problem. They won't execute
                UIManager.instance.logPanel.enabled = true;
                UIManager.instance.logPanel.text = "Servidor no disponible";
                UIManager.instance.HideUsernameSelection();
            }

            //If theres no connection to the server the function returns
            if (!socket.Connected) 
            {
                return;
            }

            //Reference to data stream
            stream = socket.GetStream();

            //Packet for data received from server
            receivedData = new Packet();

            //Read
            stream.BeginRead(receiveBuffer, 0, dataBufferSize, ReceiveCallback, null);
        }
 

Есть ли в любом случае способ заставить блок catch выполнить код внутри него?

Комментарии:

1. разъем. EndConnect, похоже, завершает соединение (согласно комментариям в коде и документах MS). Я не вижу никакого метода подключения в попытке, так почему вы ожидаете, что обнаружите ошибку?

2. Извините, я не скопировал всю функцию целиком. Я только что обновил его. Я хочу выполнить функции из UIManager, если обратный вызов при подключении к серверу отрицательный, чтобы я мог показать пользовательский интерфейс повторного подключения и ошибку сервера.

Ответ №1:

Почти уверен, что проблема в том, что этот вызов выполняется асинхронно, поэтому в другом потоке/задаче.

Большая часть API Unity может использоваться только в основном потоке Unity. (Единственным исключением являются в основном все чистые математические структуры, которые непосредственно не влияют на сцену и не зависят от нее.)

В большинстве случаев это решается с помощью так называемого «Диспетчера основного потока». Это выглядит примерно так, например.

 public class MainThreadDispatcher : MonoBehaviour
{
    #region Singleton Pattern
    private static MainThreadDispatcher _instance;

    public static MainThreadDispatcher Instance
    {
        get
        {
            if(_instance) return _instance;

            _instance = FindObjectOfType<MainThreadDispatcher>();
            
            if(_instance) return _instance;

            _instance = new GameObject(nameof (MainThreadDispatcher)).AddComponent<MainThreadDispatcher>();
        }  
    }

    private void Awake ()
    {
        if(_instance amp;amp; _instance != this)
        {
            Destroy (gameObject);
            return;
        }

        _instance = this;
        DontDestroyOnLoad(gameObject);
    }
    #endregion

    #region Dispatcher
    private readonly Queue<Action> _actions = new Queue<Action>();

    private void LateUpdate ()
    {
        lock (_actions)
        {
            while(_actions.Count > 0)
            {
                var action = _actions.Dequeue();

                action?.Invoke();
            }
        }
    }

    public void DoInMainThread(Action action)
    {
        lock(_actions)
        {
            _actions.Enqueue(action);
        }
    }
    #endregion
}
 

И тогда вы предпочли бы отправить все, что связано с Unity API, например

 try
{
    //Ends connection
    socket.EndConnect(_result);
} 
catch (Exception e) 
{
    MainThreadDispatcher.Instance.DoInMainThread(() =>
    {
        // To have the information is always helpful I'd say ;)
        Debug.LogWarning($"{e.GetType()} - {e.Message}/n{e.StackTrace}");
        UIManager.instance.logPanel.enabled = true;
        UIManager.instance.logPanel.text = "Servidor no disponible";
        UIManager.instance.HideUsernameSelection();
    }
}
 

Комментарии:

1. @alex2furious, я рад слышать, что ваша проблема решена, вы можете нажать » ✔ » для соответствующего ответа в качестве ответа. Это также поможет другим решить аналогичную проблему.