80

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

我有这个工作,TaskCompletionSource但那个类是通用的,并且返回一个对象,就像Task<bool>我想要的只是一个Task没有返回值的普通对象。

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此代码中返回的内容。我正在寻找与此不同的解决方案。

4

5 回答 5

101

该方法可以更改为:

public Task ShowAlert(object message, string windowTitle)

Task<bool>继承自,Task因此您可以返回,同时只向调用者Task<bool>公开Task

编辑:

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

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

于 2012-08-15T12:27:42.360 回答
56

如果您不想泄露信息,常用的方法是使用TaskCompletionSource<object>并完成null. 然后将其作为Task.

于 2012-08-15T12:59:17.360 回答
18

.NET 5 有一个非通用的TaskCompletionSource.

它被添加到这个拉取请求中:https ://github.com/dotnet/runtime/pull/37452/files#diff-4a72dcb26e2d643c337baef9f64312f3

于 2020-08-12T08:20:07.623 回答
3

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

于 2015-07-25T17:28:42.383 回答
1

来自@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/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# 语法中的一个严重设计缺陷。

于 2016-08-22T23:19:23.317 回答