Вопрос

я читал Природа TaskCompletionSource, сообщение Стивена Тауба.

public static Task RunAsync(Action action)
{
    var tcs = new TaskCompletionSource<Object>();
    ThreadPool.QueueUserWorkItem(_ =>
    {
        try
        {
            action();
            tcs.SetResult(null);
        }
        catch(Exception exc) { tcs.SetException(exc); }
    });
    return tcs.Task;
}

Поскольку нас больше не волнует, какой тип T то есть я по умолчанию использовал Object.Затем, когда Action выполняется успешно, SetResult до сих пор используется для перехода Task в RanToCompletion конечное состояние;однако, поскольку фактическое значение результата не имеет значения, null используется. Окончательно, RunAsync возвращает Task скорее, чем Task<Object>.Конечно, экземпляр taskтип все еще Task<Object>, но нам не нужно ссылаться на него как таковой, и потребителю этого метода не нужно беспокоиться об этих деталях реализации.

Я не особенно понимаю, почему метод должен возвращать Task скорее, чем Task<object> (поэтому я подчеркнул жирное предложение).Я знаю, что метод настроен на возврат Task но tcs это TaskCompletionSource<Object>, нет TaskCompletionSource (что, я думаю, неправильно).

Это было полезно?

Решение

Не существует универсального TaskCompletionSource а учитывая, что все, что вам нужно, — это задача без результата, результат не имеет значения.Вызывающая сторона не знает и в данном случае ее не волнует, что Задача на самом деле является Task<object>, Звонивший только что awaitЭто так, и получает исключение, если оно есть.Вызывающий не знает фактического результата.

Этому, конечно, способствует тот факт, что Task<T> наследует от Task


Также часто можно найти Task<bool> который возвращает false, или Task<int> с 0.

Другие советы

Не существует неуниверсального TaskCompletionSource класс для создания экземпляров Task которые не являются экземплярами Task<T>.Это оставляет два варианта параметра универсального типа для TaskCompletionSource<T> когда вас не волнует (или не предоставляете) возвращаемое значение:

  1. Используйте произвольный существующий тип, например object, в качестве возвращаемого типа.Установите значение null для обозначения завершения задачи.
  2. Используйте определенный закрытый тип и установите значение null для обозначения завершения задачи.

Когда я создаю TaskCompletionSource<T> экземпляр с целью предоставления Task без возвращаемого значения, я предпочитаю использовать выделенный закрытый тип, чтобы гарантировать, что потребляющий код не ошибется с возвращаемым значением. Task как пример Task<T> где результат имеет значение.

Сначала я определяю следующий класс (это может быть private sealed class если он вложен в другой тип):

internal sealed class VoidResult
{
}

Тогда вместо использования TaskCompletionSource<object> для источника завершения я использую TaskCompletionSource<VoidResult>.Поскольку VoidResult тип недоступен при вызове кода, пользователь не сможет привести Task возражать против экземпляра Task<VoidResult>.

Я не особенно понимаю, почему метод должен возвращать Task скорее, чем Task<object>

Потому что когда ты вернешься Task<Object> это означает, что когда этот метод завершится, он выдаст какое-то полезное значение типа Object.в данном случае мы не даем никакого результата. Вот почему Стивен решил вернуться. Task.

Если мы имеем дело с Func<Object> потом возвращаюсь Task<Object> было бы уместно, так как Func даст некоторый результат, мы можем решить вернуть его.

Почему TaskCompletionSource<Object>, нет TaskCompletionSource?

Потому что такого нет.Не существует нестандартного TaskCompletionSource.

Если вы вернули Task<object>, затем var result = await RunAsync(...) всегда возвращался бы null, поскольку именно для этого вы устанавливаете результат.

Клиента это не волнует, поэтому вы просто возвращаете Task.

В идеале вы должны использовать TaskCompletionSource внутри, вместо TaskCompletionSource<object>, и просто позвоните что-то вроде SetCompleted() вместо SetResult(null).Но такого типа не существует.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top