Вызов асинхронного метода из неасинхронного метода - PullRequest
6 голосов
/ 09 декабря 2011

Все варианты следующего кода, которые я пробую, не работают - будь то 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 Task Action будет сложнее позже.Когда это действие завершится, как бы долго это ни заняло, я ожидал, что Task (или другие механизмы Framework) возобновятся, присвоив "Howdy ..." x, а затем - y.То, что я ДЕЙСТВИТЕЛЬНО хочу сделать, это перехватить ожидаемые объекты, обработать их и через некоторое время, которое я контролирую, возобновить продолжение с результатом (x и y).Но я не очень далеко продвинулся на этом большом шаге, поэтому я пытаюсь начать с меньшего.

Ответы [ 3 ]

11 голосов
/ 09 декабря 2011

Сначала прочтите документ Асинхронный шаблон на основе задач.Это под My Documents\Microsoft Visual Studio Async CTP\Documentation.Этот документ описывает, как проектировать API, естественно потребляемые await.

. Во-вторых, осознайте, что есть несколько аспектов класса Task и связанных API, которые больше не применяются в новом асинхронном мире.Task изначально был написан как ядро ​​TPL.Он оказался подходящим для асинхронного программирования, поэтому Microsoft использовала его вместо создания нового класса Promise.Но есть ряд методов, которые используются TPL, но не нужны для асинхронного программирования.

Чтобы ответить на главный вопрос, смешивание синхронного и асинхронного кода не совсем однозначно с текущей асинхронной CTP.Я написал библиотеку , которая включает метод расширения Task.WaitAndUnwrapException, который позволяет легко вызывать асинхронный код из кода синхронизации.Вас также может заинтересовать мой AsyncContext класс , который делает ненужным запрос «нажать любую клавишу».

5 голосов
/ 09 декабря 2011

Задания, которые вы возвратили, еще не начались (т. Е. Это «холодные» задания);попробуйте заменить код PrepareAwaitable следующим:

static Task<string> PrepareAwaitable(int x)
{
    return Task.Factory.StartNew<string>(() =>
    {
        return "Howdy " + x.ToString();
    });
}
5 голосов
/ 09 декабря 2011

Не совсем понятно, чего вы пытаетесь достичь, потому что в этом нет ничего асинхронного.Например, он скомпилируется и запустится, но я не знаю, хотите ли вы этого:

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);
}

Это больше похоже на то, что вы искали?

...