Как написать простой асинхронный метод?

Используя последний CTP5 с ключевыми словами async/await, я написал код, который, по-видимому, не может скомпилироваться:

 class Program
    {
        public class MyClass
        {
            async public Task<int> Test()
            {
                var result = await TaskEx.Run(() =>
                    {
                        Thread.Sleep(3000);
                        return 3;
                    });
                return result;
            }
        }

        static void Main(string[] args)
        {
            var myClass = new MyClass();

            //The 'await' operator can only be used in a method or lambda marked with the 'async' modifier error ??!!
            int result = await myClass.Test();

            Console.ReadLine();
        }
    }

В чем причина того, что «Оператор ожидания» может использоваться только в методе или лямбда-выражении, помеченном ошибкой модификатора «асинхронный»?» (Я выбрал строку, на которую указывает Visual Studio)


person ghord    schedule 21.07.2011    source источник


Ответы (3)


Я не знаю, можно ли пометить Main как асинхронный, но вам нужно включить ключевое слово async в объявление любого метода, использующего await. Например:

public async void DoStuffAsync ()
{
    var myClass = new MyClass ();

    int result = await myClass.TestAsync ();
}
person Bodrick    schedule 21.07.2011
comment
Вы можете объявить Main как async, и await что-либо в нем завершит вашу программу (при условии, что у вас нет других запущенных потоков переднего плана). - person dlev; 21.07.2011
comment
Да, я все думал, что ошибка внутри моего метода Test. Visual Studio должна быть более информативной с этой ошибкой (например, метод Main должен быть асинхронным). - person ghord; 21.07.2011
comment
В выпуске C#5, если вы пометите Main как асинхронный, вы получите сообщение об ошибке: точка входа не может быть помечена модификатором 'async' - person Anthony; 10.09.2012

await не совпадает с Wait(); выполнение await является значительным переписыванием этого метода и, в частности, влияет на ожидание того, как этот метод завершается для вызывающей стороны. Вы правы в том, что на самом деле он мало что делает (осторожно: возвращаемые типы), за исключением того, что он сообщает компилятору включить некоторые вещи (как и такие переключатели, как unsafe, checked и unchecked, если вы думаете об этом) - но учтите: на самом деле это имеет значение чрезвычайно в вашем примере. Если Main() завершится (и мы предполагаем, что других потоков нет) - ваш exe подожжен. Прошло. Более не существует. Добавление async заставляет вас думать, что только потому, что метод выходит, не означает, что он завершен. Вы действительно не хотите, чтобы Main() вышел, прежде чем вы будете готовы.

В качестве вторичного эффекта этот переключатель также формализует, что метод может возвращать только такие вещи, как Task; без переключателя у вас может возникнуть соблазн сделать его асинхронным позже, что может оказаться серьезным изменением.

person Marc Gravell    schedule 21.07.2011
comment
@dlev хороший Монти Пайтон там ;p - person Marc Gravell; 21.07.2011

Асинхронный метод может иметь возвращаемый тип void или Task. Если возвращаемый тип не пуст, вызывающая сторона все равно может использовать стандартный механизм ожидания, представленный в .Net 4, внутри основного метода записи (который нельзя пометить как асинхронный). Вот простой пример:

    static void Main(string[] args)
    {
        string address = "http://api.worldbank.org/countries?format=json";
        Task t = LoadJsonAsync(address);
        // do other work while loading
        t.Wait();

        Console.WriteLine("Hit ENTER to exit...");
        Console.ReadLine();
    }

    private async static Task LoadJsonAsync(string address)
    {
        HttpClient client = new HttpClient();

        HttpResponseMessage response = await client.GetAsync(address);

        // Check that response was successful or throw exception
        response.EnsureSuccessStatusCode();

        // Read response asynchronously as JsonValue and write out top facts for each country
        JsonArray readTask = await response.Content.ReadAsAsync<JsonArray>();
        Console.WriteLine("First 50 countries listed by The World Bank...");
        foreach (var country in readTask[1])
        {
            Console.WriteLine("   {0}, Capital: {1}",
                country.Value["name"],
                country.Value["capitalCity"]);
        }

    }
person Andrew Scoppa    schedule 10.05.2012
comment
Я ненавижу то, что все всегда используют client.GetAsync в качестве примера. Постер, вероятно, знает, как использовать чужой асинхронный метод. Как вы пишете его?? (например, используя пример Sleep) - person Jeff; 06.12.2012
comment
Что делать, если ваша асинхронная задача возвращает результат? Вызов task.wait возвращает логическое значение. Как бы вы ждали, а затем использовали возвращенный результат? РЕДАКТИРОВАТЬ: Неважно. Task.Result. - person Kyle; 20.04.2013
comment
не уверен, но разве вам не нужно запускать Task t перед тем, как ждать () для него? t.Start(); t.Wait(); - person Prokurors; 11.03.2015