Задача возврата вместо задачи <TResult> из TaskCompletionSource
Как я видел в нескольких примерах , а также, что я могу понять из этого Вопрос SO > Я должен иметь возможность вернуть не-общую задачу из TaskCompletionSource
(i.e., Return Task and not Task<TResult> from the method UploadFilesAsync)
Однако следующий код:
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
var tcs = new TaskCompletionSource<Object>();
//logic to process files
try
{
await Task.WhenAll(uploadFileAAsync(fileAPath),
uploadFileBAsync(fileBPath));
tcs.TrySetResult(null);
}
catch (Exception e)
{
tcs.SetException(e);
}
finally
{
//logic to clean up files
}
return tcs.Task;
}
Производит следующую синтаксическую ошибку
'UploadFilesAsync(string, string)' is an async method that returns 'Task',
a return keyword must not be followed by an object expression.
Did you intend to return 'Task<T>'?
Я нацелен на .NET 4.5. Я знаю, что он может работать, чтобы вернуть задачу (объекта), но это делает интерфейс API "грязным". Предпочитает ли практика возвращать задачу (объекта) или можно вернуть задачу (не общее, как показано в коде)?
Ответы
Ответ 1
Я знаю, что он может работать, чтобы вернуть задачу (объекта)
Ну, это не будет делать то, что вы ожидаете.
Проблема в том, что вы пытаетесь вернуть задачу... а метод async автоматически обертывает возвращаемое значение в другую задачу. Непонятно, почему вы используете метод асинхронного использования здесь, если быть честным. Почему бы просто не написать это:
public Task UploadFilesAsync(string fileAPath, string fileBPath)
{
return Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}
Разве это не делает то, что вы хотите? Вам просто нужна задача, которая завершается, когда завершаются обе "подоперации", верно? Именно это возвращает Task.WhenAll
. Ваш метод по-прежнему не блокируется - он не будет ждать завершения операций до его возвращения. Просто вы используете тот факт, что Task.WhenAll
не блокирует это, вместо метода async.
EDIT: обратите внимание: если вы хотите сделать что-то еще в этом методе, вы можете сделать его асинхронным методом, не используя TaskCompletionSource
самостоятельно:
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
// Upload the files
await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
await SomethingElseAsync();
MaybeDoSomethingCheap();
}
Обратите внимание, что даже если метод async здесь возвращает Task
, у вас нет возвращаемого значения - механизм async/await обрабатывает все это для вас, возвращая задачу, которая будет завершена, когда MaybeDoSomethingCheap()
будет завершена, или ошибка, если выбрано исключение.
Ответ 2
Насколько я знаю, нет прямого способа вернуть объект Task
при использовании TaskCompletionSource<T>
.
Обычно я предпочитаю возвращать объект типа Task<bool>
в этих ситуациях. Но вы правы в том, что возврат объекта типа общего назначения не имеет смысла, если возвращаемые значения функции не используются.
Но на самом деле вам не нужно создавать TaskCompletionSource
, так как в этой функции есть ключевое слово await
. TaskCompletionSource
обычно используется для преобразования синхронной функции в асинхронную. Поскольку вы уже вызываете асинхронную функцию (и на самом деле это кажется единственной функцией), вам не нужно создавать TaskCompletionSource
.
public async Task UploadFilesAsync(string fileAPath, string fileBPath)
{
return await Task.WhenAll(uploadFileAAsync(fileAPath), uploadFileBAsync(fileBPath));
}