首页 文章

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

提问于
浏览
4

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

无法将类型'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 回答

  • 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 异步(特别是不应该只用于UI事件处理程序的 async void ) .

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

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

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

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

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

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

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

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

    • 如果函数是异步的,则只能在函数中使用await

    • 异步函数返回Task而不是void和Task <TResult >而不是TResult .

    • 等待任务 <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.
    }
    

相关问题