Поделиться через


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