【问题标题】:Calling an async method with c#5.0使用 c#5.0 调用异步方法
【发布时间】:2026-01-16 22:15:01
【问题描述】:

我使用 C# 5.0 的新异步模式 (async/await) 进行了一些测试,但在理解如何调用异步方法时遇到了问题。

考虑到这段代码:

private async Task<string> DownloadAsync()
    {
        progress.ProgressChanged += (s, e) =>
            {
                progressBar1.Value = e.value;
            };

            return await DownloadSomething(myurl, progress);

    }

private async void CallDownloadAsync()
    {
        string text = await DownloadAsync();
        progressBar1.Value = 0;
        label1.Text = "Done!";
    }

private void button4_Click(object sender, EventArgs e)
    {
        CallDownloadAsync();
    }

所以,这段代码运行良好。当我单击“button4”时,下载任务开始并且我的 ProgressBar 已正确更新。

但是,我想通过删除这样的 CallDownloadAsync() 方法来进一步压缩我的代码:

private void button4_Click(object sender, EventArgs e)
    {
        new Action(async () =>
        {
            string result = await Task.Run<string>(() => DownloadAsync());
        }).Invoke();
        label1.Text = "Running...";
    }

所以在这里,我想直接启动一个调用 DownloadAsync 方法的操作,但是当我点击我的 Button4 时,我在进度条上出现了一个跨线程操作无效。所以我不明白 Action() 和 CallDownloadAsync() 方法的调用之间的主要区别是什么。

【问题讨论】:

    标签: c# task-parallel-library async-await c#-5.0 synchronizationcontext


    【解决方案1】:

    您可能会发现我的async/await intro 很有帮助。特别是,async 方法不在后台线程上运行; Task.Run 用于在后台线程上运行某些东西,因此您的代码有所不同。

    一般来说,您应该避免使用async void,除非您正在编写async 事件处理程序。像这样:

    private async void button4_Click(object sender, EventArgs e)
    {
        label1.Text = "Running...";
        string result = await DownloadAsync();
        progressBar1.Value = 0;
        label1.Text = "Done!";
    }
    

    【讨论】:

      【解决方案2】:

      不同之处在于,在前一种情况下,您从 UI 线程(上下文)调用 CallDownloadAsync()

      在后一种情况下,DownloadAsync() 从启动的任务中调用,该任务通常在由 TPL(任务并行库)创建的 UI 线程或由它创建的线程之外的不同线程中执行。

      在 WPF 中,UI 组件只能由专用 UI​​ 线程或从其下创建的(其子)线程(即具有相同的 UI 上下文)访问。

      【讨论】: