С# Может ли "метод задачи" также быть "асинхронным" методом?
Я пытаюсь получить руку от нового асинхронного CTP-материала, и я, вероятно, запутываю себя здесь..
У меня может быть этот "метод задачи", без проблем:
public static Task<String> LongTaskAAsync() {
return Task.Run(() => {
return("AAA");
});
}
Но что, если мне понадобится задача для выполнения другой задачи, я могу пометить ее как "асинхронную" и использовать "ожидание"? Я попробовал это:
public async static Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return Task.Run(() => {
return("AAA");
});
}
Но тогда таинственно получаю эту ошибку компилятора: поскольку это асинхронный метод, возвращаемое выражение должно иметь тип 'string', а не Task<string>
Что мне здесь не хватает?
Ответы
Ответ 1
Возможно, вы захотите прочитать мой async
/await
пост вступления.
Возвращаемые значения из методов async
заключены в Task<TResult>
. Аналогично, await
разворачивает возвращаемые значения:
public static async Task<String> LongTaskAAsync() {
await Task.Delay(2000);
return await Task.Run(() => {
return("AAA");
});
}
Обоснование этого описано в моей Async "Почему так работают ключевые слова" Неофициальный FAQ.
P.S. Вы также можете использовать Task.FromResult
для простых тестов, подобных этому.
Изменить: Если вы хотите создать и вернуть сам объект Task
, то метод не должен быть async
. Одним из наиболее распространенных шаблонов является метод public
non async
, который вызывает только часть async
.
Например, какой-то асинхронный кеш - если объект находится в кеше, то немедленно возвращайте его; в противном случае, асинхронно создайте его, добавьте в кэш и верните его (это пример кода, а не потокобезопасный):
public static Task<MyClass> GetAsync(int key)
{
if (cache.Contains(key))
return Task.FromResult(cache[key]);
return CreateAndAddAsync(key);
}
private static async Task<MyClass> CreateAndAddAsync(int key)
{
var result = await CreateAsync(key);
cache.Add(key, result);
return result;
}
Ответ 2
Может ли "метод задачи" также быть "асинхронным" методом?
Да, это может быть, просто изменив подпись метода на public async static Task<Task<String>> LongTaskAAsync()
, так как это то, что он вернет.
Если вы используете ключевое слово async
, среда выполнения вернет тип, возвращаемый в задачу, чтобы включить асинхронность. Скажем, если вы вернете string
, среда выполнения перенесет это в Task<string>
. int
пойдет Task<int>
, а Task<string>
пойдет Task<Task<string>>
. См. Это консольное приложение для очистки:
public class Program
{
public static void Main(string[] args)
{
// start the main procedure asynchron
Task.Run(() => DoIt()).Wait();
}
// for async support since the static main method can't be async
public static async void DoIt()
{
Program p = new Program();
// use the methods
string s = await p.GetString();
int i = await p.GetInt();
Task<string> tsk = await p.GetTaskOfString();
// just to prove the task works:
// C# 5
string resultFromReturnedTask = await tsk;
// C# 4
string resultFromReturnedTask2 = tsk.Result;
}
public async Task<string> GetString()
{
return "string";
}
public async Task<int> GetInt()
{
return 6;
}
public async Task<Task<string>> GetTaskOfString()
{
return Task.Run(() => "string");
}
}