1

这是我的代码:

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

1 回答 1

5

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

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

TestConnection().Wait()

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

于 2013-05-27T02:02:02.127 回答