【问题标题】:Cannot implicitly convert type 'void' to 'System.Threading.Tasks.Task'无法将类型“void”隐式转换为“System.Threading.Tasks.Task”
【发布时间】:2015-03-16 07:54:08
【问题描述】:

下面是我的代码的简化版本,它会产生以下编译错误

无法将类型“void”隐式转换为“System.Threading.Tasks.Task”

在这种情况下,GetDataAsync 方法不需要返回任何内容。我怎样才能让它返回一个我可以等待的任务?

static async void Run()
{
    List<string> IDs = new List<string>() { "a", "b", "c", "d", "e", "f" };
    Task[] tasks = new Task[IDs.Count];
    for (int i = 0; i < IDs.Count; i++)
        tasks[i] = await GetDataAsync(IDs[i]);

    Task.WaitAll(tasks);    
}

async static Task GetDataAsync(string id)
{
    var data = await Task.Run(() => GetDataSynchronous(id));
    // some other logic to display data in ui
}

【问题讨论】:

  • GetDataAsync 正在返回一个任务,但是,Run 不是。 async void 只能用于事件处理程序。

标签: c# .net task-parallel-library async-await task


【解决方案1】:

由于您尝试将所有调用的结果存储到GetDataAsync(这些都是任务),因此您不应该等待它们。只需删除await,收集所有任务并在最后等待它们。

static void Run()
{
    List<string> IDs = new List<string>() { "a", "b", "c", "d", "e", "f" };
    Task[] tasks = new Task[IDs.Count];
    for (int i = 0; i < IDs.Count; i++)
        tasks[i] = GetDataAsync(IDs[i]);

    Task.WaitAll(tasks);    
}

此外,由于您正在与 Task.WaitAll 同步等待,因此根本不需要使 Run 异步(尤其不是 async void,它应该只用于 UI 事件处理程序)。

如果您想异步等待,则创建 Run async void(仅当它是 UI 事件处理程序时)并使用 Task.WhenAll(tasks) 一起等待所有任务:

static async void Run()
{
    await Task.WhenAll(new[] {"a", "b", "c", "d", "e", "f"}.Select(GetDataAsync));
}

【讨论】:

    【解决方案2】:

    异步函数的返回值是 Task 而不是 void 和 Task&lt;TResult> 而不是 TResult。

    如果您将函数更改为以下内容,它将是正确的:

    private static async Task Run()
    {
        ...
        await ...
    }
    

    有一个例外,异步事件处理程序可能返回 void:

    private async void OnButton1_clicked(object sender, ...)
    {
        await Run();
    }
    

    这足以让您的 UI 在任务运行时保持响应。

    • 如果你的函数是异步的,你只能在函数中使用 await
    • 异步函数返回 Task 而不是 void 和 Task&lt;TResult> 而不是 TResult。
      • await Task&lt;TResult>的值为TResult。
      • 只有异步函数可以使用所有其他异步函数。

    如果你有一个非异步函数,并且你想在做其他事情的同时启动一个任务,你可以使用下面的代码:

    private void MyFunction()
    {
        // do some processing
        // start a separate task, don't wait for it to finish:
        var myTask = Task.Run( () => MyAsyncFunction(...))
        // while the task is running you can do other things
        // after a while you need the result:
        TResult result = await myTask;
        ProcessResult(result);
    }
    

    您甚至可以启动多个任务,在它们处理的同时做其他事情,然后等待任务完成:

    private async void OnButton1_clicked(object sender, ...)
    {
        var Tasks = new List<Task>();
        for (int i=0; i<10; ++i)
        {
            Tasks.Add(Run());
        }
        // while all tasks are scheduled to run, do other things
        // after a while you need the result:
        await Task.WhenAll(tasks);
        // Task.WhenAll(...) returns a Task, so await Task.WhenAll returns void
        // async functions that return Task`<TResult`> has a Result property 
        // that has the TResult value when the task if finished:
        foreach (var task in tasks)
        {
            ProcessResult(task.Result);
        }
        // not valid for your Run(), because that had a Task return value.
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-01-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多