为什么`async void`是C#语言的必要部分?

时间:2017-01-13 16:10:08

标签: c# async-await

为什么async void是C#的一部分的常见描述适用于事件处理程序。例如:

private async void button_Click(object sender, RoutedEventArgs e)
{
    using (var httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync("http://example.com");
        var content = await response.Content.ReadAsStringAsync();
        this.textBox.Text = content;
    }
}

我发现这个原因并不令人满意,因为这种事件处理程序可以在没有async void的情况下编写,如下所示:

private void button_Click(object sender, RoutedEventArgs e)
{
    button_ClickAsync().ForgetTask();
}

private async Task button_ClickAsync()
{
    using (var httpClient = new HttpClient())
    {
        var response = await httpClient.GetAsync("http://example.com");
        var content = await response.Content.ReadAsStringAsync();
        this.textBox.Text = content;
    }
}

static class TaskExtensions { public static void ForgetTask(this Task task) { } }

为什么后者不够好?为什么async void是C#的必要部分?没有async void会无法解决什么问题?

3 个答案:

答案 0 :(得分:2)

当你展示自己时,它不是必要的。您可以在不使用它的情况下将功能相同的程序写入使用它的程序。它是有用的,因为有时你确实想要创建一个async方法,它不会暴露任何观察结果的方法,例如你提到的情况。他们是否可以用这样的方式设计这个功能,用户可以用另一种方式完成,是的,你展示了一种可能的方式,C#语言设计师选择另一种方式。

答案 1 :(得分:1)

未启动的async Task方法的异常将被忽略,触发TaskScheduler.UnobservedTaskException事件。例如:

    static void Main()
    {
        TaskScheduler.UnobservedTaskException += (object sender, UnobservedTaskExceptionEventArgs args) => { Console.WriteLine(args.Exception.InnerException.Message + " unobserved"); };
        try
        {
            ThrowExceptionInAsyncTask();
            Console.WriteLine("ThrowExceptionInAsyncTask not caught");
        }
        catch (Exception)
        {
            Console.WriteLine("ThrowExceptionInAsyncTask caught");
        }
        GC.Collect();
        try
        {
            ThrowExceptionInAsyncVoid();
            Console.WriteLine("ThrowExceptionInAsyncVoid not caught");
        }
        catch (Exception)
        {
            Console.WriteLine("ThrowExceptionInAsyncVoid caught");
        }
        GC.Collect();
    }

    static async Task ThrowExceptionInAsyncTask()
    {
        throw new InvalidOperationException("ThrowExceptionInAsyncTask");
    }

    static async void ThrowExceptionInAsyncVoid()
    {
        throw new InvalidOperationException("ThrowExceptionInAsyncVoid");
    }

产地:

ThrowExceptionInAsyncTask not caught
ThrowExceptionInAsyncVoid not caught
ThrowExceptionInAsyncTask unobserved

答案 2 :(得分:0)

根据我自己的知识,它在两种情况下使用:

  1. 在事件处理程序中。因为事件处理程序不能有返回类型。
  2. 用于没有返回类型且未等待的方法。
  3. 您在此处所做的是一个很好的解决方法,但将其视为语言的灵活性,以使开发人员的生活更轻松并简化语言语法。与你的相同的例子是:为什么System.Linq存在于C#中?为什么我们可以使用像myIntArray.Max()这样的语法,同时我们可以迭代数组并找到最大值!

    这并不意味着没有其他原因,但我在分享我的想法,我希望有所帮助。