【问题标题】:Non-Generic TaskCompletionSource or alternative非通用 TaskCompletionSource 或替代
【发布时间】:2020-08-12 16:20:07
【问题描述】:

我正在使用通常异步显示的警报窗口 (Telerik WPF)(代码在打开时继续运行),我想通过使用 async/await 使其同步。

我有这个使用TaskCompletionSource,但是这个类是通用的,当我想要一个没有返回值的普通Task时返回一个像Task<bool>这样的对象。

public Task<bool> ShowAlert(object message, string windowTitle)
{
    var dialogParameters = new DialogParameters { Content = message };

    var tcs = new TaskCompletionSource<bool>();
    dialogParameters.Closed += (s, e) => tcs.TrySetResult(true);

    RadWindow.Alert(dialogParameters);

    return tcs.Task;
}

调用该方法的代码是

await MessageBoxService.ShowAlert("The alert text.")

如何返回一个功能相似的非通用任务,我可以等待直到dialogParameters.Closed 事件触发?我知道我可以忽略此代码中返回的bool。我正在寻找与此不同的解决方案。

【问题讨论】:

    标签: c# .net async-await


    【解决方案1】:

    方法可以改成:

    public Task ShowAlert(object message, string windowTitle)
    

    Task&lt;bool&gt; 继承自 Task,因此您可以返回 Task&lt;bool&gt;,同时仅将 Task 暴露给调用者

    编辑:

    我找到了一个 Microsoft 文档 http://www.microsoft.com/en-us/download/details.aspx?id=19957,由 Stephen Toub 撰写,标题为“基于任务的异步模式”,其中包含以下摘录,推荐了相同的模式。

    TaskCompletionSource 没有非泛型对应项。但是,Task 派生自 Task,因此通用 TaskCompletionSource 可用于 I/O 绑定方法,这些方法通过使用具有虚拟 TResult 的源(布尔值是一个很好的默认选择,并且如果开发人员担心 Task 的使用者将其向下转换为 Task,则可以使用私有 TResult 类型)

    【讨论】:

      【解决方案2】:

      如果您不想泄露信息,常用的方法是使用TaskCompletionSource&lt;object&gt; 并以null 的结果完成。然后将其返回为Task

      【讨论】:

        【解决方案3】:

        .NET 5 有一个非泛型 TaskCompletionSource

        在此拉取请求中添加了它:https://github.com/dotnet/runtime/pull/37452/files#diff-4a72dcb26e2d643c337baef9f64312f3

        【讨论】:

          【解决方案4】:

          Nito.AsyncEx 实现了一个非泛型 TaskCompletionSource 类,归功于上面的 @StephenCleary 先生。

          【讨论】:

          • 已被删除,在源码中发现:非泛型TaskCompletionSource已被删除。请改用TaskCompletionSource&lt;object&gt;
          【解决方案5】:

          来自@Kevin Kalitowski

          我找到了一个 Microsoft 文档 http://www.microsoft.com/en-us/download/details.aspx?id=19957,由 Stephen Toub 撰写,标题为“基于任务的异步模式”

          我认为本文档中有一个示例可以解决 Kevin 指出的问题。这是一个例子:

          public static Task Delay(int millisecondsTimeout)
          {
              var tcs = new TaskCompletionSource<bool>();
              new Timer(self =>
              {
                  ((IDisposable)self).Dispose();
                  tcs.TrySetResult(true);
              }).Change(millisecondsTimeout, -1);
              return tcs.Task;
          }
          

          一开始我觉得不好,因为不能在没有编译信息的情况下直接在方法中添加“async”修饰符。但是,如果您稍微更改方法,该方法将使用 async/await 进行编译:

          public async static Task Delay(int millisecondsTimeout)
          {
              var tcs = new TaskCompletionSource<bool>();
              new Timer(self =>
              {
                  ((IDisposable)self).Dispose();
                  tcs.TrySetResult(true);
              }).Change(millisecondsTimeout, -1);
              await tcs.Task;
          }
          

          编辑:起初我以为我已经克服了困难。但是,当我在我的应用程序中运行等效代码时,此代码只会让应用程序在等待 tcs.Task; 时挂起。所以,我仍然认为这是 async/await c# 语法中的一个严重设计缺陷。

          【讨论】:

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