处理BeginInvoke异常的方法

本文关键字:方法 异常 BeginInvoke 处理 | 更新日期: 2023-09-27 18:02:14

有时您需要在特定线程上运行特定代码,例如winforms。为了让代码在UI线程上运行,你需要这样的东西:

this.BeginInvoke(new MethodInvoker(() =>
{
   try
   {
       //code
   }
   catch(Exception ex)
   {
       HandleException(ex);
   }
}

SynchorixationContext是做同样事情的另一种方式。

假设我们知道我们需要在UI线程中运行特定的代码,并且我们有一种特定的方法来处理在这个UI线程上抛出的异常(BeginInvoke没有阻塞,因此不会传输异常(。我们如何才能创建一种方法,使同样的事情变得更简单:

RunOnUIThread(MyMethod);

RunOnUIThread将包含与此代码中的第一个示例大致相同的代码。

有可能创建这样的方法吗?如果是,怎么办?

处理BeginInvoke异常的方法

您可以编写一些不错的扩展方法,比如这个

public static class ControlExtension
{
    public static IAsyncResult BeginInvokeWithExceptionHandling(this Control control, Action method, Action<Exception> exceptionHandler)
    {
        if (control == null) throw new ArgumentNullException("control");
        if (method == null) throw new ArgumentNullException("method");
        if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
        return control.BeginInvoke(new MethodInvoker(() =>
        {
            try
            {
                method();
            }
            catch (Exception ex)
            {
                exceptionHandler(ex);
            }
        }));
    }
    public static IAsyncResult BeginInvokeWithExceptionHandling<T>(this Control control, Delegate method, Action<Exception> exceptionHandler, params object[] args)
    {
        if (control == null) throw new ArgumentNullException("control");
        if (method == null) throw new ArgumentNullException("method");
        if (exceptionHandler == null) throw new ArgumentNullException("exceptionHandler");
        return control.BeginInvoke(new MethodInvoker(() =>
        {
            try
            {
                method.DynamicInvoke(args);
            }
            catch (Exception ex)
            {
                exceptionHandler(ex);
            }
        }));
    }
}

如何使用:

private void HandleException(Exception ex)
{
}
private void MyMethod()
{
}
this.BeginInvokeWithExceptionHandling(MyMethod, HandleException);

注意:由于Delegate.DynamicInvoke,这可能会降低性能,您可以使用强类型委托来修复它。同样值得注意的是,如果control.BeginInvoke找不到委托类型,它也会在内部使用Delegate.DynamicInvoke

public static void InvokeControlAction<t>(t cont, Action<t> action) where t : Control
{
    if (cont.InvokeRequired)
    { cont.Invoke(new Action<t, Action<t>>(InvokeControlAction), 
                new object[] { cont, action }); }
    else
    { action(cont); }
}

CodeProject参考

根据Sriram的建议,我最终完成了这个:

public static void SendToUIThread(Action method, bool UseExceptionHandling = true)
        {
            if (method == null)
                throw new ArgumentNullException("method is missing");
            _threadSyncContext.Send(new SendOrPostCallback(delegate(object state)
            {
                if (UseExceptionHandling)
                {
                    try
                    {
                        method();
                    }
                    catch (Exception ex)
                    {
                        ErrorController.Instance.LogAndDisplayException(ex, true);
                    }
                }
                else
                    method();
            }), null);
        }
        public static void PostOnUIThread(this Control control, Action method, bool UseExceptionHandling = true)
        {
            if (method == null)
                throw new ArgumentNullException("method is missing");
            if (control.InvokeRequired)
                PostOnUIThread(method, UseExceptionHandling);
            else
            {
                if (UseExceptionHandling)
                {
                    try { method(); }
                    catch (Exception ex) { ErrorController.Instance.LogAndDisplayException(ex, true); }
                }
                else
                    method();
            }
        }