非通用TaskCompletionSource或替代

时间:2012-08-15 12:24:29

标签: c# .net async-await

我正在使用通常以异步方式显示的警报窗口(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。我正在寻找一种不同的解决方案。

5 个答案:

答案 0 :(得分:84)

该方法可以更改为:

public Task ShowAlert(object message, string windowTitle)

Task<bool>继承自Task,因此您只需将Task<bool>公开给来电者即可返回Task

修改

我找到了Stephen Toub的一份名为“基于任务的异步模式”的Microsoft文档http://www.microsoft.com/en-us/download/details.aspx?id=19957,它有以下摘录,推荐使用相同的模式。

  

TaskCompletionSource&lt; TResult&gt;没有非通用对应物。但是,Task&lt; TResult&gt;派生自Task,因此通用TaskCompletionSource&lt; TResult&gt;可以用于I / O绑定方法,它只是通过使用带有虚拟TResult的源返回Task(布尔值是一个很好的默认选择,如果开发人员担心任务的消费者将其向下转换为任务&lt; TResult&gt ;,可以使用私有的TResult类型)

答案 1 :(得分:45)

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

答案 2 :(得分:6)

.NET 5具有非通用的TaskCompletionSource

它是在以下请求请求中添加的:https://github.com/dotnet/runtime/pull/37452/files#diff-4a72dcb26e2d643c337baef9f64312f3

答案 3 :(得分:3)

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

答案 4 :(得分:1)

来自@Kevin Kalitowski

  

我发现了一个名为“基于任务的异步模式”的微软文档http://www.microsoft.com/en-us/download/details.aspx?id=19957&#39;

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

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;
}

起初我认为这不好,因为你无法直接添加&#34; async&#34;没有编译消息的方法的修饰符。但是,如果稍微更改方法,该方法将使用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#语法中一个严重的设计缺陷。