C#异步-未处理异常

C#异步-未处理异常,c#,C#,当无法连接到服务器时,此代码不会处理引发的异常。你知道为什么吗?谢谢 public Form1() { InitializeComponent(); StartClient(); } async private Task StartClient() { try { await ConnectToServerAsync(); } catch (System.Net.So

当无法连接到服务器时,此代码不会处理引发的异常。你知道为什么吗?谢谢

public Form1()
        {
            InitializeComponent();
            StartClient();

        }
async private Task StartClient()
{
    try
    {
        await ConnectToServerAsync();
    }
    catch (System.Net.Sockets.SocketException)
    {
        MesssageBox.Show("TEST");
    }
}

private Task ConnectToServerAsync()
{
    return Task.Factory.StartNew(() => client.Connect(host, port));
}
问题是:“async void”是一个非常危险的构造,几乎不应该出现在您的产品代码中。异步方法在内部不是一个语句列表,它是一种状态机,可以从一个“wait”语句切换到另一个“wait”,在“waiting”语句之间执行各种操作。因此,一旦在状态机中引发异常,就需要特殊的上下文来保留堆栈跟踪等。Void方法不提供这样的上下文。返回任务或任务

作为进一步的阅读,我可以推荐Phil Haack非常好的博客帖子:

问题是:“async void”是非常危险的构造,几乎不应该出现在生产代码中。异步方法在内部不是一个语句列表,它是一种状态机,可以从一个“wait”语句切换到另一个“wait”,在“waiting”语句之间执行各种操作。因此,一旦在状态机中引发异常,就需要特殊的上下文来保留堆栈跟踪等。Void方法不提供这样的上下文。返回任务或任务


作为进一步的阅读,我可以推荐Phil Haack非常好的博客帖子:

这段代码有各种各样的问题。首先,使用
async void
仅适用于事件处理程序。不能等待
异步void
方法,也不能处理它引发的任何异常。其次,
Task.Factory.StartNew(()=>client.Connect(主机,端口))
伪造异步执行。它仍然会阻塞线程。异步执行意味着在等待操作完成时没有线程被阻塞

我假设您使用TcpClient。此类已经有一个以异步方式连接的方法。您可以将代码简化为:

private async Task StartClient()
{
    try
    {
        await client.ConnectAsync(host,port);
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.ToString());
    }
}
如果要启动客户端以响应UI事件(例如,单击按钮),则应编写:

async void Button1_Click(object sender, EventArgs e)
{
    await StartClient();
}


最后,使用日志库而不是
MessageBox.Show
,例如
log4net
,这样您就不会因为线程问题而丢失异常消息

此代码存在各种问题。首先,使用
async void
仅适用于事件处理程序。不能等待
异步void
方法,也不能处理它引发的任何异常。其次,
Task.Factory.StartNew(()=>client.Connect(主机,端口))
伪造异步执行。它仍然会阻塞线程。异步执行意味着在等待操作完成时没有线程被阻塞

我假设您使用TcpClient。此类已经有一个以异步方式连接的方法。您可以将代码简化为:

private async Task StartClient()
{
    try
    {
        await client.ConnectAsync(host,port);
    }
    catch (Exception exc)
    {
        MessageBox.Show(exc.ToString());
    }
}
如果要启动客户端以响应UI事件(例如,单击按钮),则应编写:

async void Button1_Click(object sender, EventArgs e)
{
    await StartClient();
}


最后,使用日志库而不是
MessageBox.Show
,例如
log4net
,这样您就不会因为线程问题而丢失异常消息

await
将所有异常包装在AggregateException中-您应该首先捕获该异常,然后检查
AggregateException.InnerExceptions
集合是否存在导致错误的实际异常即使捕获了未处理的所有异常也不要使用
async void
。它不能等待,它引发的任何异常都无法处理。它只适用于事件处理程序为什么要这样调用
Task.Factory.StartNew
?为什么不执行
任务。运行
?更好的是,为什么不使用异步版本的Connect?例如,当
Task.Run(()=>client.Connect())
只是假装时,它是一个真正的异步方法it@Fabio
Task.Result
抛出一个
aggregateeexception
await
抛出发生的异常
await
将所有异常包装在AggregateException中-您应该首先捕获该异常,然后检查
AggregateException.InnerExceptions
集合以查找导致错误的实际异常即使我捕获了未处理的所有异常也不要使用
async作废
。它不能等待,它引发的任何异常都无法处理。它只适用于事件处理程序为什么要这样调用
Task.Factory.StartNew
?为什么不执行
任务。运行
?更好的是,为什么不使用异步版本的Connect?例如,当
Task.Run(()=>client.Connect())
只是假装时,它是一个真正的异步方法it@Fabio
Task.Result
抛出一个
aggregateeexception
wait
抛出发生的异常感谢您的回答。不,我不使用TcpClient,我使用一个处理客户机-服务器-通信的外部库。即使我将StartClient的返回类型更改为Task,它也不起作用(其他所有内容都保留在我最初的帖子中)@azmd108首先,异常会起作用。你试过调试吗?您是否在
catch
语句中设置了断点?你确定有例外情况吗?如果执行没有进入异常处理程序,那是因为没有要处理的异常。另一方面,如果从控制台应用程序调用
async void
方法,应用程序可能会在该方法有机会运行之前终止,而不是跳入Catch语句中-这是我的问题-它没有捕获。是,存在System.Net.Sockets.SocketExceptionthrown@azmd108发布重现问题的实际代码。谁调用
StartClient
?你在等待它完成吗?如果用
抛出新异常()
替换
客户机.Connect
,会发生什么情况?发现如果我执行已编译的程序集,catch块会很好地触发,只有在调试catch块时才会触发。这是为什么?谢谢你的回答。不,我不使用TcpClient,我使用一个处理客户机-服务器-通信的外部库。即使我更改了St的返回类型