c#中Result和ContinueWith的区别

本文关键字:区别 ContinueWith Result | 更新日期: 2023-09-27 18:09:23

这两个似乎做同样事情的方法之间有什么区别?即使使用async/await也能做到吗?

public Task<int> TaskMaxAsync1 ( Task<int>[] my_ints )
{
    return Task.WhenAll( my_ints )
    .ContinueWith ( x => x.Result.Where ( i => i%2 != 0 ).Max( ) ) ;
}
public Task<int> TaskMaxAsync2 ( Task<int>[] my_ints )
{
    var numbers = Task.WhenAll( my_ints ).Result ;
    return Task.FromResult( numbers.Where( i => i%2 != 0 ).Max( ) ) ;
}

c#中Result和ContinueWith的区别

Result与ContinueWith的差异

Result将同步阻塞直到任务完成,并将异常包装在AggregateException中。

ContinueWith将向任务注册回调,并在任务完成时调用该回调。

对于异步代码,ResultContinueWith都应该替换为await

它可以做,甚至async/await?

当然可以,像这样:

public async Task<int> MaxAsync(Task<int>[] my_ints)
{
  int[] ints = await Task.WhenAll(my_ints);
  return ints.Where(i => i % 2 != 0).Max();
}

这两种方法之间的区别是什么同样的事情吗?

区别在于前者向调用者返回一个热任务,而后者同步阻塞,然后使用Task.FromResultTask中重新包装结果。后者也是死锁的常见情况,如果您在具有自定义SynchronizationContext的环境中运行。

它可以做,甚至async/await?

可以:

public async Task<int> MaxAsync(Task<int>[] myInts)
{
    int[] results = await Task.WhenAll(myInts);
    return results.Max(i => i % 2 != 0 ? i : (int?)null) ?? 0;
}

task0.Result将同步阻塞并等待task0完成,而task1.ContinueWith不会等待task1完成,而是返回一个新的Task(将在task1完成时运行)。

所以,你的例子中的两个方法的行为是不一样的。在第二个方法中,如果my_ints在传递给WhenAll方法时没有全部运行完成,那么.Result将同步阻塞调用线程,无论my_ints中的所有任务需要多长时间才能完成,如果其中一些抛出异常,TaskMaxAsync2抛出异常。

然而,第一个方法将立即返回,即使my_ints永远不会结束或抛出异常。