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

时间:2015-01-17 23:28:57

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

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

  

无法隐式转换类型' 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
}

2 个答案:

答案 0 :(得分:8)

由于您尝试将所有调用的结果存储到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);    
}

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

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

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

答案 1 :(得分:1)

异步功能的返回值是任务而不是空白和任务<TResult&gt;而不是TResult。

如果您将功能更改为以下内容将是正确的:

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

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

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

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

  • 如果您的函数是异步
  • ,则只能在函数中使用await
  • 异步函数返回Task而不是void和Task <TResult&gt;而不是TResult。
    • 等待任务<TResult&gt;的价值,是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.
}