Вызов асинхронного метода из неасинхронного метода
Каждый вариант следующего кода, который я пробую, не работает - будь DoSomething() : void
и называется как написано, или DoSomething() : Task
и называется с TaskEx.RunEx()
Некоторая попытка с участием .GetAwaiter().GetResult()
, Видимые ошибки включают в себя: "Start may not be called on a task with null action"
, "RunSynchronously may not be called on a task unbound to a delegate"
, а также "The task has not yet completed"
,
class Program
{
static void Main(string[] args) // Starting from a non-async method
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static Task<string> PrepareAwaitable(int id)
{
return new Task<string>(() =>
{
return "Howdy " + id.ToString();
});
}
}
Выход:
Начиная DoSomething ...
Нажмите любую клавишу, чтобы выйти.
PrepareAwaitable
"s Task
"s Action
будет сложнее позже. Когда это действие завершится, сколько бы времени это ни заняло, я бы ожидал Task
(или другие рамочные механизмы) возобновить, назначив "Howdy ..."
к х, а затем к у. Что я ДЕЙСТВИТЕЛЬНО хочу сделать, так это перехватить ожидаемые объекты, обработать их и через некоторое время, которыми я управляю, возобновить продолжение с результатом (x
а также y
). Но я не очень далеко продвинулся в этом большом шаге, поэтому я пытаюсь начать с меньшего.
4 ответа
Задания, которые вы возвратили, еще не начались (то есть, они являются "холодными" заданиями); попробуйте заменить код PrepareAwaitable следующим:
static Task<string> PrepareAwaitable(int x)
{
return Task.Factory.StartNew<string>(() =>
{
return "Howdy " + x.ToString();
});
}
Сначала прочитайте документ по асинхронному шаблону на основе задач. Это под My Documents\Microsoft Visual Studio Async CTP\Documentation
, Этот документ описывает, как проектировать API, естественно потребляемые await
,
Во-вторых, осознайте, что есть несколько аспектов Task
класс и связанные API, которые больше не применяются в новом асинхронном мире. Task
Первоначально был написан как ядро TPL. Он оказался подходящим для асинхронного программирования, поэтому Microsoft использовала его вместо создания нового класса Promise. Но ряд методов являются задержками, используемыми TPL, но не необходимыми для асинхронного программирования.
Чтобы ответить на основной вопрос, смешивание синхронного и асинхронного кода не совсем просто с текущей асинхронной CTP. Я написал библиотеку, которая включает в себя Task.WaitAndUnwrapException
метод расширения, который облегчает вызов асинхронного кода из кода синхронизации. Вы также можете быть заинтересованы в моем AsyncContext
класс, который делает запрос "нажать любую клавишу" ненужным.
Не совсем понятно, чего вы пытаетесь достичь, потому что в этом нет ничего асинхронного. Например, это скомпилирует и запустит, но я не знаю, хотите ли вы этого:
using System;
using System.Threading.Tasks;
class Program
{
static void Main(string[] args)
{
DoSomething();
Console.WriteLine("Press any key to quit.");
Console.ReadKey();
}
static async void DoSomething()
{
Console.WriteLine("Starting DoSomething ...");
var x = await PrepareAwaitable(1);
Console.WriteLine("::" + x);
var y = await PrepareAwaitable(2);
Console.WriteLine("::" + y);
}
static async Task<string> PrepareAwaitable(int x)
{
return "Howdy " + x;
}
}
Обратите внимание, что это дает предупреждение для PrepareAwaitable
потому что в этом нет ничего асинхронного; никаких "жду" выражений. Вся программа выполняется синхронно. Еще одна альтернативная реализация PrepareAwaitable
:
static Task<string> PrepareAwaitable(int x)
{
return TaskEx.Run(() => "Howdy " + x);
}
Это больше похоже на то, что вы преследовали?
Добавить