Створіть виконане завдання <T>


125

Я впроваджую метод, Task<Result> StartSomeTask()і випадково знаю результат вже до того, як метод буде викликаний. Як створити завдання <T> , яке вже виконано?

Це те, що я зараз роблю:

private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var task = new Task<Result>(() => theResult);
    task.RunSynchronously(CurrentThreadTaskScheduler.CurrentThread);
    return task;
}

Чи є краще рішення?


6
Зауважте, що відповіді на це запитання також спрацьовують для створення простого завдання (немає <T>), оскільки завдання <T> успадковується від завдання.
Тім Ловелл-Сміт

Зауважте, що сьогодні є ValueTaskвиконані завдання (тобто для значень, які ви вже маєте, щоб код був по суті синхронним), що заощадить вам розподіл.
nawfal

Відповіді:


111
private readonly Result theResult = new Result();

public override Task<Result> StartSomeTask()
{
    var taskSource = new TaskCompletionSource<Result>();
    taskSource.SetResult(theResult);
    return taskSource.Task;
}

@DanielLobo ви можете отримати відповідь, якщо ви поясните, що таке заперечення
user2023861

1
Чи не повинен бути той, що нижче, простіший і з набагато більшим числом голосів? @ user2023861
Даніель Лобо

203

Для націлювання на .NET 4.5 ви можете використовувати Task.FromResult:

public static Task<TResult> FromResult<TResult>(TResult result);

Щоб створити невдале завдання, використовуйте Task.FromException:

public static Task FromException(Exception exception);
public static Task<TResult> FromException<TResult>(Exception exception);

.NET 4.6 додає, Task.CompletedTaskякщо вам потрібен не загальний Task.

public static Task CompletedTask { get; }

Обхідні шляхи для старих версій .NET:

  • Якщо ви орієнтуєтесь на .NET 4.0 з пакетом орієнтації на Async (або AsyncCTP), ви можете використовувати це TaskEx.FromResultзамість.

  • Щоб отримати загальний Taskдо .NET 4.6, ви можете використовувати той факт, що Task<T>походить від Taskта просто дзвонити Task.FromResult<object>(null)або Task.FromResult(0).


13
Щоб повернути загальне завдання, краще використовувати щось на зразок Task.FromResult (0). Використання "null" в якості параметра може переплутати компілятор, який не може визначити загальний параметр.
Whyllee

Що з винятками? Методи асинхронізації компілюються в державну машину, яка фіксує винятки і зберігає їх у поверненому завданні. Це трапляється навіть для виконання коду до першого очікування. Метод повернення Task.FromResult може викидати винятки безпосередньо.
Роберт Важан

@ RobertVažan Цікавий крайній випадок. Можливо, якщо ви отримуєте відомий результат з методу, і цей метод викидає винятки, тоді є дефект, який потребує виправлення.
Гусдор

1
@ RobertVažan Ви можете легко написати свій власний FromExceptionметод, який веде себе так, FromResultале натомість являє собою несправне завдання. Такий метод може просто повернути це для випадків помилок, якщо важливо, щоб виняток був представлений в результаті завдання.
Сервіс

1
Task.FromException недоступний у .NET 4.5 ... Я думаю, це слід вказати.
STiLeTT

12

Для завдань, що не мають значення повернення, .NET 4.6 додав Task.CompletedTask .

Він повертає завдання, яке вже є у TaskStatus.RanToCompletion. Ймовірно, кожен раз повертає один і той же екземпляр, але документація попереджає вас не розраховувати на цей факт.



1

Виклик завдання. Коли всі параметри повернуть виконане завдання.

Task task = Task.WhenAll();

Хоча це спрацює, це незрозуміле рішення, яке може заплутати людей при читанні коду, оскільки воно передбачає очікування завдань, яких не існує
Адріан Христов
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.