【问题标题】:awaiting inside an awaitable function in .net在 .net 中的可等待函数中等待
【发布时间】:2022-01-12 06:41:21
【问题描述】:

我有一个返回任务的函数

    class Sample
    {
       TaskCompletionSource<int> _tcs;
    ..
       public Task<int> DoIt(){
         StartDoingStuff();
         return _tcs.Task;
       }
      ..
    
      private void FinshedStuffCallBack(){
        _tsc.SetResult(42);
      }
    }

来电者去

 var sample = new Sample();
  var result = await Sample.DoIt();

工作正常

现在我需要在DoIt中做一些额外的事情,这本身就是等待的

我天真地尝试过

       public async Task<int> DoIt(){
        
         await DoOtherAsyncStuff();
          StartDoingStuff();
         return _tcs.Task;
       }

但这是不允许的

CS4016 由于这是一个异步方法,返回表达式必须是 输入“int”而不是“任务”

好的,我明白它的意思,但这不是我的意图,我还没有返回值,它会在 StartDoingStuff 触发回调时出现。

不确定下一步该尝试什么。

【问题讨论】:

  • 你的代码的目标对我来说不是很清楚,但你可能想要return await _tcs.Task
  • 我相信你明白.. 不能编译,所以我猜这不是你的真实代码。我们真的很想得到一个minimal reproducible example 能够提供适当的帮助..
  • @StevenFontanella 目标是 StarDoingStuff() 在 DoOtherAsyncStuff 完成之前无法运行。 StartDoingStuff 启动一些将在未来某个时间完成的东西——它在完成时调用 FinishedStuffCallback。 DoIt 的调用者需要等到 StartDoingStuff 完成并从该完成中获取结果

标签: c# async-await


【解决方案1】:

您很可能只需要(注意最后一行的await):

       public async Task<int> DoIt()
       {
           await DoOtherAsyncStuff();
           StartDoingStuff();
           return await _tcs.Task;
       }

最后一行需要await,因为返回Task&lt;int&gt;async函数需要返回int,而_tcs.TaskTask&lt;int&gt;。使用await 将等待任务完成并返回我们需要的int

但是,根据您的完整代码,您可能需要其他内容。例如,如果您使用 TaskCompletionSource 做更复杂的事情,您可能需要为此定义删除 async 并执行类似的操作

       public Task<int> DoIt()
       {
           return DoOtherAsyncStuff().ContinueWith(_ => 
               {
                   StartDoingStuff();
                   return _tcs.Task;
               }, TaskCompletionOptions.ExecuteSynchronously);
       }

一般来说,最好不要乱用 TaskCompletionSource,除非您正在做一些更高级的事情,例如提供基于同步/回调的异步抽象。因此,一个完整的代码示例可能会改变我的答案(例如 StartDoingStuff + DoOtherAsyncStuff 的正文是什么?)。

【讨论】:

  • 那行得通 - ty。我永远不会猜到它。如果我不使用 TaskCompleteionSource,我如何表示我返回的 Task 对象现在已完成并设置其结果。 MS 文档在如何创建真正的可等待对象(即等待稍后事件回调的对象)方面非常糟糕
  • TaskCompletionSource 是这样做的正确方法,但是您的设计在这里看起来很脆弱;似乎很多事情都需要以正确的顺序发生才能不发生死锁。另外,如果StartDoingStuff 是同步的,为什么会有回调?如果它在后台进行工作,那么它可能应该是异步的并使用Task.Run。如果它是同步的并且在同一个线程上运行,那么我们可以完全消除 TaskCompletionSource 并使其成为一个正常的函数调用,因为在这种情况下与它相关的所有工作无论如何都是同步的。
  • StartDoingstuff 启动一个音频侦听器,该侦听器一直等待,直到它听到播放的特定音符集或发生超时。然后,该侦听器调用回调来指示它所听到的内容。 DoOtherAsync 的东西正在渲染一些 UI,侦听器用来显示进度(所有这些都是 Blazor WASM)
猜你喜欢
  • 2019-12-12
  • 2023-03-13
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 2019-06-16
  • 2018-02-03
  • 2020-06-10
  • 1970-01-01
相关资源
最近更新 更多