C# 为什么TcpClient.Connect即使异步方法正在同步运行,也不会在异步方法中引发异常 为什么即使未指定等待,此代码也不会引发System.Net.Sockets.SocketException?(没有服务器在指定端口侦听)

C# 为什么TcpClient.Connect即使异步方法正在同步运行,也不会在异步方法中引发异常 为什么即使未指定等待,此代码也不会引发System.Net.Sockets.SocketException?(没有服务器在指定端口侦听),c#,.net,multithreading,asynchronous,async-await,C#,.net,Multithreading,Asynchronous,Async Await,为什么线程。睡眠(4000);没有被执行吗 public class AsyncTcpClientDemos { private static readonly ILog Logger = LogProvider.GetCurrentClassLogger(); public async Task ConnectTcpClientNoException() { Logger.Debug("ConnectTcpClientNoException() - start

为什么线程。睡眠(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);
   }
}
从NUnit测试中调用方法:

[Test]
public void AsyncTcpClientNoExceptionTest()
{
    var asyncAwait = new AsyncTcpClientDemos();

    // TODO: find out why this is not throwing exception
    asyncAwait.ConnectTcpClientNoException();            
}

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

之所以不执行睡眠,是因为异常确实阻止了方法的其余部分执行——只是异常通过
任务
传播,而不是直接在堆栈上传播

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

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
}
publictasync(intx,inty)
{
if(x
异步方法从不直接引发异常。相反,如果在方法体中引发异常,则异步方法返回的任务将出现故障

之所以不执行睡眠,是因为异常确实阻止了方法的其余部分执行——只是异常通过
任务
传播,而不是直接在堆栈上传播

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

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
}
publictasync(intx,inty)
{
if(x
为什么此代码甚至没有抛出System.Net.Sockets.SocketException 如果没有指定等待

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

[Test]
public async Task AsyncTcpClientNoExceptionTest()
{
    var asyncAwait = new AsyncTcpClientDemos();
    await asyncAwait.ConnectTcpClientNoException();            
}
即使通过同步阻塞,您也可以看到(正如@luan所建议的那样)(只是为了说明这一点,实际上不要使用它):

当您使用
async void
时,您将强制执行一种“触发并忘记”的执行方式,在这种方式下,您将完全放弃出现故障的任务。这恰恰产生了吞咽异常的不希望的行为。如果您注册,您将能够看到,当任务完成时,将触发此事件

为什么线程。睡眠(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);
   }
}
正如John所说,因为异常确实发生了,所以它不会反映在您编写的代码中。将执行更改为正确等待任务将显示这一点

为什么此代码甚至没有抛出System.Net.Sockets.SocketException 如果没有指定等待

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

[Test]
public async Task AsyncTcpClientNoExceptionTest()
{
    var asyncAwait = new AsyncTcpClientDemos();
    await asyncAwait.ConnectTcpClientNoException();            
}
即使通过同步阻塞,您也可以看到(正如@luan所建议的那样)(只是为了说明这一点,实际上不要使用它):

当您使用
async void
时,您将强制执行一种“触发并忘记”的执行方式,在这种方式下,您将完全放弃出现故障的任务。这恰恰产生了吞咽异常的不希望的行为。如果您注册,您将能够看到,当任务完成时,将触发此事件

为什么线程。睡眠(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);
   }
}

正如John所说,因为异常确实发生了,所以它不会反映在您编写的代码中。将任务的执行更改为正确等待将显示这一点。

您不能忽略
wait
。尝试执行类似于
AsyncWait.ConnectTcpClientNoException().GetWaiter().GetResult()
的操作-这将导致在测试方法中引发异常。否则它就被丢弃了(更确切地说,留在返回的任务中,但忽略返回值时这对您没有任何帮助)。或者只是AsyncWait.ConnectTcpClientNoException().Wait()您不能忽略
Wait
。尝试执行类似于
AsyncWait.ConnectTcpClientNoException().GetWaiter().GetResult()
的操作-这将导致在测试方法中引发异常。否则它就被丢弃了(更确切地说,留在返回的任务中,但忽略返回值时这对您没有任何帮助),或者只是AsyncWait.ConnectTcpClientNoException().Wait(),我使用了
async task
。但是
异步无效
也有同样的行为。@Andriy F是否会传播异常?不,在这两种情况下都不会。是否打开了第一次机会异常?我没有在调试模式下运行此[测试]。我使用了
异步任务
。但是
async void
也有同样的行为。@Andriy F是否会传播异常?不,在这两种情况下都不会。是否打开了第一次机会异常?我不会在调试模式下运行此[测试]