Task.FromResult 可能返回单一实例

Task.FromResult<TResult>(TResult) 现在可能返回缓存的 Task<TResult> 实例,而不是始终创建新的实例。

旧行为

在以前的版本中,Task.FromResult<TResult>(TResult) 始终分配新的 Task<TResult>,而不考虑 T 的类型或结果值。

新行为

对于某些 T 类型和某些结果值,Task.FromResult<TResult>(TResult) 可能会返回缓存的单一实例对象,而不是分配新的对象。 例如,可能每次对 Task.FromResult(true) 的调用都将返回相同的已完成的 Task<bool> 对象。

引入的版本

.NET 6

中断性变更的类型

此项更改可能会影响二进制兼容性

更改原因

许多开发人员预计 Task.FromResult<TResult>(TResult) 的行为与已经执行此类缓存的异步方法类似。 了解分配行为的开发人员通常会保留自己的缓存,以避免始终为这些常用值分配的性能成本。 例如:

private static readonly Task<bool> s_trueTask = Task.FromResult(true);

现在,Boolean 和小 Int32 值等值不再需要此类自定义缓存。

除非使用引用相等性来检查一个 Task 实例是否与另一个 Task 实例相同,否则不应受到此更改的影响。 如果你使用此类引用相等性,并且需要继续此检查,请使用以下代码确保便始终返回唯一的 Task<TResult> 实例:

private static Task<T> NewInstanceFromResult<T>(T result)
{
    var tcs = new TaskCompletionSource<T>();
    tcs.TrySetResult(result);
    return tcs.Task;
}

注意

这种模式比仅使用 Task.FromResult(result) 效率要低得多,除非你真的需要它,否则应该避免。

受影响的 API