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

8
以下是我简化后的代码,它会生成以下编译错误:

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

在这种情况下,GetDataAsync方法不需要返回任何内容。我该如何使其返回一个可等待的任务(Task)?
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
}

3
GetDataAsync返回一个任务,但是Run没有。async void应该仅用于事件处理程序。 - John Koerner
2个回答

13

由于您正在尝试存储所有调用GetDataAsync返回的任务结果,因此不应该使用await。只需删除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异步化(特别是不应该使用仅适用于UI事件处理程序的async void),因为您使用Task.WaitAll同步等待。

如果您想要异步等待,则需要将Run改为async void(仅当它是UI事件处理程序时),然后使用Task.WhenAll(tasks)来同时等待所有任务:

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

1

异步函数的返回值是 Task 而不是 void,Task<TResult> 而不是 TResult。

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

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

有一个例外情况,异步事件处理程序可以返回void:
private async void OnButton1_clicked(object sender, ...)
{
    await Run();
}

这已经足够使您的UI在任务运行时保持响应了。
  • 只有在函数是async的情况下才能使用await。
  • 异步函数返回Task而不是void,返回Task<TResult>而不是TResult。
    • await Task<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.
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接