为什么TcpClient.Connect不会在异步方法中抛出异常,即使它是同步运行的

时间:2015-07-07 13:18:58

标签: c# .net multithreading asynchronous async-await

  1. 为什么即使没有指定await,此代码也不会抛出System.Net.Sockets.SocketException? (没有服务器正在侦听指定的端口)
  2. 为什么选择Thread.Sleep(4000);没有执行?

    public class AsyncTcpClientDemos
    {
       private static readonly ILog Logger = LogProvider.GetCurrentClassLogger();
    
       public async Task ConnectTcpClientNoException()
       {
           Logger.Debug("ConnectTcpClientNoException() - start");
           var tcp = new TcpClient();
           tcp.Connect("127.0.0.1", 9045);
           Thread.Sleep(4000);
       }
    }
    
  3. 从NUnit测试中调用方法:

    [Test]
    public void AsyncTcpClientNoExceptionTest()
    {
        var asyncAwait = new AsyncTcpClientDemos();
    
        // TODO: find out why this is not throwing exception
        asyncAwait.ConnectTcpClientNoException();            
    }
    

2 个答案:

答案 0 :(得分:6)

async方法永远不会直接抛出异常。相反,如果在方法体内引发异常,则异步方法返回的任务将出现故障。

睡眠未执行,因为异常阻止方法的其余部分执行 - 只是异常通过Task传播而不是直接堆叠。

如果您真的希望方法的第一部分抛出异常,可以将其拆分为两个。例如:

public Task FooAsync(int x, int y)
{
    if (x < y)
    {
        // This will be thrown straight to the caller, in the
        // normal way
        throw new ArgumentException("...");
    }
    return FooAsyncImpl(x, y);
}

private async Task FooAsyncImpl(int x, int y)
{
    // Any exceptions thrown here will be propagated via the task
}

答案 1 :(得分:3)

  

为什么这段代码不会抛出System.Net.Sockets.SocketException   如果没有指定await?

正是因为如此。你还没有等待返回的任务。如果您愿意等待,您会看到异常传播:

[Test]
public async Task AsyncTcpClientNoExceptionTest()
{
    var asyncAwait = new AsyncTcpClientDemos();
    await asyncAwait.ConnectTcpClientNoException();            
}

即使通过同步阻止你也可以看到(正如@Luann所建议的那样)(只是为了明确说明,不要实际使用它):

[Test]
public void AsyncTcpClientNoExceptionTest()
{
    var asyncAwait = new AsyncTcpClientDemos();
    asyncAwait.ConnectTcpClientNoException().GetAwaiter().GetResult();
}

当您使用async void时,您就会强行解雇并忘记&#34;执行方式,您完全放弃故障任务。这恰好产生了吞咽异常的不良行为。如果您注册TaskScheduler.UnobservedTaskException,您将能够看到当任务完成时,此事件将会触发。

  

为什么选择Thread.Sleep(4000);没有执行?

正如John所说,因为实际上发生了,但它并没有反映在您编写的代码中。将执行更改为正确等待任务将向您显示。