c# 处理主线程无法全局捕捉子线程内部异常的方案之一(扩展重载Task.Factory.StartNew)

搞winform界面的时候,很多地方用异步处理,又懒得个个写catch,所有弄这个来用用

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace MethodExtension
{
    public static class Method
    {
        /// <summary>
        /// 捕捉线程内部异常并抛回主线程,多参数委托
        /// </summary>
        /// <param name="task"></param>
        /// <param name="action"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static Task StartNew(this TaskFactory task, Action<object[]> action, params object[] param)
        {
            var t = task.StartNew((sc) =>
            {
                try
                {
                    action.Invoke(param);
                }
                catch (Exception ex)
                {
                    ((SynchronizationContext)sc).Post((p) =>
                    {
                        throw (Exception)p;
                    }, ex);
                }
            }, SynchronizationContext.Current);
            return t;
        }
    }
}

使用

            Task.Factory.StartNew((p) =>
            {
                var temp = _dal.GetSendTriger(Setting.SelectSort);
                dataGridView1.BeginInvoke((Action)(() =>
                {
                    label8.Text = "共" + temp.Rows.Count + "条记录";
                    dataGridView1.DataSource = temp;
                }));
            });
            Task.Factory.StartNew((p) =>
            {
                var a=p[0];
                var b=p[1];
            },"参数1",1);
            Task.Factory.StartNew((p) =>
            {
                var b=p[0];
            },"a");

全局捕捉

			//方式1
			AppDomain.CurrentDomain.UnhandledException += (sender, e) =>
            {
                MessageBox.Show(e.ExceptionObject.ToString(), "提示");
            };
            //方式2
            Application.ThreadException += (sender, e) =>
            {
                MessageBox.Show(e.Exception.Message, "提示");
            };

-----------------------------------------2021年3月27日00:59:11---------------------------------------------
注意…
在非UI线程里SynchronizationContext.Current可能会为null,所以改为直接重新实例一个SynchronizationContext,并且异常以字符串形式抛出,异常可以更加详细

public static class TaskEx
    {
        /// <summary>
        /// 捕捉线程内部异常并抛回主线程,多参数委托
        /// </summary>
        /// <param name="task"></param>
        /// <param name="action"></param>
        /// <param name="param"></param>
        /// <returns></returns>
        public static Task StartNewEx(this TaskFactory task, Action<object[]> action, params object[] param)
        {
            var t = task.StartNew((sc) =>
            {
                try
                {
                    action.Invoke(param);
                }
                catch (Exception ex)
                {
                    ((SynchronizationContext)sc).Post((p) =>
                    {
                        throw new Exception(((Exception)p).ToString());
                    }, ex);
                }
            }, new SynchronizationContext());
            return t;
        }

        /// <summary>
        /// 捕捉线程内部异常并抛回主线程
        /// </summary>
        /// <param name="task"></param>
        /// <param name="action"></param>
        /// <returns></returns>
        public static Task RunEx(this TaskFactory task, Action action)
        {
            SynchronizationContext context = new SynchronizationContext();
            var t = Task.Run(() =>
            {
                try
                {
                    action.Invoke();
                }
                catch (Exception ex)
                {
                    context.Post((p) =>
                    {
                        throw new Exception(((Exception)p).ToString());
                    }, ex);
                }
            });
            return t;
        }
    }
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C#中,可以使用`Task.Factory.StartNew`方法来启动一个后台线程,并使用`Invoke`方法在UI线程上更新`Chart`控件,以避免卡顿UI。以下是一个示例代码: ```csharp using System; using System.Threading.Tasks; using System.Windows.Forms; using System.Windows.Forms.DataVisualization.Charting; class Program { static void Main(string[] args) { var chart = new Chart(); chart.Series.Add("Series1"); chart.ChartAreas.Add("ChartArea1"); chart.ChartAreas[0].AxisX.Minimum = 0; chart.ChartAreas[0].AxisX.Maximum = 10; chart.ChartAreas[0].AxisY.Minimum = 0; chart.ChartAreas[0].AxisY.Maximum = 100; var form = new Form(); form.Controls.Add(chart); form.Load += (sender, e) => { Task.Factory.StartNew(() => { var random = new Random(); var i = 0; while (true) { var value = random.Next(0, 100); chart.Invoke((Action)(() => { chart.Series["Series1"].Points.AddXY(i, value); if (chart.Series["Series1"].Points.Count > 10) { chart.ChartAreas[0].AxisX.Minimum = chart.Series["Series1"].Points[chart.Series["Series1"].Points.Count - 10].XValue; chart.ChartAreas[0].AxisX.Maximum = chart.Series["Series1"].Points[chart.Series["Series1"].Points.Count - 1].XValue; } })); Task.Delay(1000).Wait(); // 每隔1秒钟执行一次循环 i++; } }, TaskCreationOptions.LongRunning); }; Application.Run(form); } } ``` 在这个示例中,我们创建了一个`Chart`控件,并在`Form`中显示它。在`Form`的`Load`事件处理程序中,我们使用`Task.Factory.StartNew`方法来启动一个后台线程,并在其中执行循环。在循环中,我们使用`Invoke`方法来在UI线程上更新`Chart`控件。我们还检查了`Chart`中点的数量,以便在添加新点后自动调整`Chart`的`AxisX`范围,以保持最近的10个点可见。最后,我们使用`Application.Run`方法来运行`Form`并显示`Chart`控件。 请注意,在使用`Invoke`方法时,必须将更新UI的代码封装在一个`Action`委托中,以便它可以在UI线程上执行。此外,我们使用了`TaskCreationOptions.LongRunning`选项来告诉.NET运行时,该任务将运行较长时间,并可能在后台线程上使用较多的资源。最后,我们在`Task.Delay`后面调用了`.Wait()`方法来确保在执行下一次循环之前等待1秒钟,以避免在后台线程上卡顿UI。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值