17

Using latest CTP5 with async/await keywords, I wrote some code, which apparently cannot compile:

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

What is th reason of "The 'await' operator can only be used in a method or lambda marked with the 'async' modifier error?" (I've selected the line which Visual Studio point me to)

ghord
  • 13,260
  • 6
  • 44
  • 69

3 Answers3

8

I don't know if you can mark Main as async, but you need to include the async keyword in the declaration of any method that uses await. For example:

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

    int result = await myClass.TestAsync ();
}
Bodrick
  • 332
  • 2
  • 6
  • 1
    You *can* declare `Main` as `async`, and `await`ing anything in it *will* end your program (assuming you have no other foreground threads running.) – dlev Jul 21 '11 at 07:53
  • Duh, I kept thinking that the error is inside my Test method. The Visual Studio should be more informative with this error (like "method Main must async") – ghord Jul 21 '11 at 07:55
  • 8
    In the C#5 release, if you mark Main as async, you get an error: "An entry point cannot be marked with the 'async' modifier" – Anthony Sep 10 '12 at 11:01
4

An async method can have a return type of void or Task. If the return type is not void the caller can still use the standard Wait mechanism introduced in .Net 4 inside the Main entry method (which can not be marked async). Here's a simple example:

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

    }
  • 27
    I hate how everyone always uses client.GetAsync as the example. The poster probably knows how to use someone else's async method. How do you *write* one?? (for example using the Sleep example) – Jeff Dec 05 '12 at 21:36
  • What if your async task returns a result? Calling task.wait returns a boolean. How would you go about waiting and then using the returned result? EDIT: Never mind. `Task.Result`. – Kyle Apr 20 '13 at 17:37
  • not sure, but don't you need to start Task t before Wait()-ing for it? `t.Start(); t.Wait();` – Prokurors Mar 11 '15 at 15:19
4

await is not the same as Wait(); doing an await is a significant re-writing of that method, and in particular affects the expectation of how that method exits to the caller. You are right in that it doesn't actually do much (caveat: return types) except tell the compiler to enable some things (as do switches like unsafe, checked and unchecked if you think about it) - but consider: this actually matters hugely in your example. If Main() exits (and we assume no other threads) - you exe is toast. Gone. No longer exists. Adding async makes you consider that just because the method exits doesn't mean it has finished. You really don't want Main() exiting before you are ready.

As a secondary effect, this switch also formalises that the method can only return things like Task; without the switch, you might be tempted to make it async later, which could be a significantly breaking change.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900