如何处理view上的子线程异常?

How to handle child thread exception on view?

我有一个小的 MVC 模式应用程序,它使用随机数据创建 UDP 数据包,并不断发送它

主视图包含控制器:

public partial class MainForm : Form
    {
        private MainController controller;

        public MainForm(MainController c)
        {
            controller = c;
            InitializeComponent();
        } 
    //...
    }

主按钮单击事件调用最终将启动仿真的方法。我将它包裹在一个 try-cath 块中,这样我就可以在视图中显示任何异常

    public partial class MainForm : Form
    {
    //...
        private void btnInitiate_Click(object sender, EventArgs e)
        {
           try
           {
             controller.initiateEmulation(txtData.Text);
           }
           catch (Exception ex)
           {  
            MessageBox.Show(ex.Message + ex.StackTrace, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
           }
        }
     }


public class MainController:IMainController
{
    private Emulator model;

    public void initiateEmulation(string data)
    {
        model = new Emulator(data);
    }
}


public class Emulator
    {
        private Thread emulatorThread;
        public String data;

        public Emulator(string data)
        {
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            //CREATES SOCKET
            while (true)
            {
              //SENDS RANDOMIZED DATA
            }       
        }
    }

问题是,我的 try-catch 块只捕获主线程中发生的异常

如何处理 emulatorThread 中的异常,以便我可以在视图中显示它们,就像在主线程中一样?

您可以通过几种有趣的方式来处理这类事情,不太确定这些是否是"best practices",如果您不熟悉这些概念,您可能需要做一些研究

首先是代表:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data", HandleEmulatorException);
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public OnException OnError;

        public delegate void OnException(Exception e);

        public Emulator(string data, OnException onError)
        {
            OnError = onError;
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

这里我给模拟器一个委托,它可以在每次发生异常时调用它,你也可以用 functions/actions:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data", HandleEmulatorException);
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public Action<Exception> OnError;


        public Emulator(string data, Action<Exception> onError)
        {
            OnError = onError;
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

相同的概念,但您不必声明委托,事件是另一个:

public class MainForm
    {
        private Emulator _emulator;

        public MainForm()
        {
            _emulator = new Emulator("data");
            _emulator.OnError += HandleEmulatorException;
        }

        public void Render()
        {
            // Do other stuff
        }

        public void HandleEmulatorException(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }

    public class Emulator
    {
        private Thread emulatorThread;
        public String data;
        public event OnException OnError;

        public delegate void OnException(Exception e);

        public Emulator(string data)
        {
            this.data = data;
            emulatorThread = new Thread(Emulate);
            emulatorThread.Start();
        }

        private void Emulate()
        {
            while (true)
            {
                try
                {
                    throw new Exception("Exception was thrown");
                }
                catch (Exception e)
                {
                    OnError(e);
                }
            }
        }
    }

同样是类似的概念,但您不必传入委托,但必须声明一个。

希望对您有所帮助