如何正确编写异步方法?

时间:2013-12-31 23:26:55

标签: c# async-await c#-5.0

所以我正在尝试学习在C#中使用'async'和'await'的基础知识,但我不确定我在这里做错了什么。我期待以下输出:

Calling DoDownload
DoDownload done
[...output here...]

但我没有得到下载的输出,我也期望“完成”,但这需要一段时间。不应该立即输出吗?另外,我似乎也无法获得字符串结果。这是我的代码:

namespace AsyncTest
{
    class Program
    {
        static void Main(string[] args)
        {
            Debug.WriteLine("Calling DoDownload");
            DoDownloadAsync();
            Debug.WriteLine("DoDownload done");
        }

        private static async void DoDownloadAsync()
        {
            WebClient w = new WebClient();

            string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
            Debug.WriteLine(txt);
        }
    }
}

2 个答案:

答案 0 :(得分:6)

要获得所需的行为,您需要在退出Main()之前等待该过程完成。为了能够判断您的流程何时完成,您需要从函数返回Task而不是void,除非void函数返回async,否则你正在处理活动。

正确运行的程序的重写版本将是

class Program
{
    static void Main(string[] args)
    {
        Debug.WriteLine("Calling DoDownload");
        var downloadTask = DoDownloadAsync();
        Debug.WriteLine("DoDownload done");
        downloadTask.Wait(); //Waits for the background task to complete before finishing. 
    }

    private static async Task DoDownloadAsync()
    {
        WebClient w = new WebClient();

        string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
        Debug.WriteLine(txt);
    }
}

因为await中的Main() {}不能await downloadTask;我必须执行Wait()功能。如果这是一个SynchronizationContext {{}}}的应用程序,我会改为async并执行此功能,这是从{{1}}调用的。

答案 1 :(得分:3)

您正在调用DoDownloadAsync()但不等待它。所以你的程序将进入下一行。但是还有另外一个问题,Async方法应该返回TaskTask<T>,如果你什么也没有返回,并且你希望你的方法是异步运行的,你应该像这样定义你的方法:

private static async Task DoDownloadAsync()
    {
        WebClient w = new WebClient();

        string txt = await w.DownloadStringTaskAsync("http://www.google.com/");
        Debug.WriteLine(txt);
    }

在Main方法中,您无法等待DoDownloadAsync,因为您无法在非异步函数中使用await关键字,并且无法使Main异步。所以考虑一下:

var result = DoDownloadAsync();

Debug.WriteLine("DoDownload done");
result.Wait();