捕获主线程中的异步异常

本文关键字:异步 异常 线程 | 更新日期: 2023-09-27 18:15:41

我的代码:

using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace TestAsync
{
    class Program
    {
        private const string conn = "Data Source=UNREACHABLESERVER;Initial Catalog=master;Integrated Security=True";
        static void Main(string[] args)
        {
            try
            {
                TestConnection();
            }
            catch
            {
                Console.WriteLine("Caught in main");
            }
        }
        private static async void TestConnection()
        {
            bool connected = false;
            using (var tokenSource = new CancellationTokenSource())
            using (var connection = new SqlConnection(conn))
            {
                tokenSource.CancelAfter(2000);
                try
                {
                    await connection.OpenAsync(tokenSource.Token);
                    connected = true;
                }
                catch(TaskCanceledException)
                {
                    Console.WriteLine("Caught timeout");
                }
                catch
                {
                    Console.Write("Caught in function");
                }
                if (connected)
                {
                    Console.WriteLine("Connected!");
                }
                else
                {
                    Console.WriteLine("Failed to connect...");
                    throw(new Exception("hi"));
                }
            }
        }
    }
}

输出为:

Caught timeout
Failed to connect...

但是随后我的程序以一个未处理的异常终止。相反,我希望我的程序在主线程中处理抛出的异常并打印出Caught in main。我怎样才能做到呢?

编辑

这是我更新的代码,我想要的工作方式:

using System;
using System.Data.SqlClient;
using System.Threading;
using System.Threading.Tasks;
namespace TestAsync
{
    class Program
    {
        private const string conn = "Data Source=UNREACHABLESERVER;Initial Catalog=MyFiles;Integrated Security=True";
        static void Main(string[] args)
        {
            try
            {
                TestConnection().Wait();
            }
            catch
            {
                Console.WriteLine("Caught in main");
            }
            Console.ReadLine();
        }
        private static async Task TestConnection()
        {
            using (var tokenSource = new CancellationTokenSource())
            using (var connection = new SqlConnection(conn))
            {
                tokenSource.CancelAfter(2000);
                await connection.OpenAsync(tokenSource.Token);
            }
        }
    }
}

捕获主线程中的异步异常

这不可能。一旦遇到第一个await,对TestConnection()的调用将返回(因此主线程上的执行将继续)。您的catch阻塞并抛出异常将在另一个线程上执行,并且主线程无法观察到。

这是避免使用async void的一个原因。如果您需要编写async void函数,它必须是完全自包含的(包括错误处理逻辑)。你最好写一个async Task函数。最简单的方法是将Main方法中的调用修改为:

TestConnection().Wait()

当然,这会导致主线程在执行函数时阻塞(在编译之前,您还必须将签名更改为async Task)。