在主线程中捕获异步异常

时间:2013-05-27 01:53:51

标签: c# sql asynchronous async-await

这是我的代码:

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);
            }
        }
    }
}

1 个答案:

答案 0 :(得分:5)

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

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

TestConnection().Wait()

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