非通用TaskCompletionSource或替代

我正在使用一个通常显示为asynchronous(代码在打开时继续运行)的警报窗口(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任务,我可以等待,直到dialogParameters.Closed事件触发? 我明白,我可以忽略在这个代码中返回的bool 。 我正在寻找一个不同的解决scheme。

该方法可以更改为:

 public Task ShowAlert(object message, string windowTitle) 

Task<bool>Taskinheritance,所以你可以返回Task<bool>而只暴露Task给调用者

编辑:

我发现了一个名为“基于任务的asynchronous模式”的Stephen Toub的Microsoft文档http://www.microsoft.com/en-us/download/details.aspx?id=19957 ,它有以下摘录这种模式。

TaskCompletionSource <TResult>不存在非generics对象。 然而,Task <TResult>派生自Task,因此通用的TaskCompletionSource <TResult>可以用于I / O绑定的方法,这些方法只需使用带有伪TResult的源返回任务(布尔值是一个很好的默认select;如果开发者关心任务的消费者将其向下转换为任务<TResult>,则可以使用私人的TResulttypes)

如果你不想泄漏信息,通常的做法是使用TaskCompletionSource<object>并且结果为null 。 然后把它作为一个Task返回。

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

来自@Kevin Kalitowski

我发现了一个名为“基于任务的asynchronous模式”的Stephen Toub的Microsoft文档http://www.microsoft.com/en-us/download/details.aspx?id=19957

凯文指出,我认为这个文件中有一个例子是关于这个问题的。 这是一个例子:

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

起初我以为这是不好的,因为你不能直接添加“asynchronous”修改器的方法没有编译信息。 但是,如果稍微更改该方法,该方法将使用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 ;. 所以,我仍然认为这是asynchronous/等待c#语法的一个严重的devise缺陷。

实际上有两个版本的“非generics” TaskCompletionSource来实现。 使用假设的types名称,可以将其理解为TaskCompletionSource<Unit>TaskCompletionSource<Bottom>

两者的区别在于前者应该定义一个没有参数的SetResult ,而后者不应该定义SetResult 。 这将使TaskCompletionSource<Bottom>Task TaskCompletionSource<Bottom>无法正常完成,但您可以取消或在某个时间将其设置为故障。

这两个选项都有它的用例,但是我认为微软并没有做出任何标准化的决定。

这是一个实现的例子

 public class TaskCompletionSourceUnit { private TaskCompletionSource<int> tcs; public TaskCompletionSourceUnit() { tcs = new TaskCompletionSource<int>(); } public TaskCompletionSourceUnit(TaskCreationOptions creationOptions) { tcs = new TaskCompletionSource<int>(creationOptions); } public TaskCompletionSourceUnit(object state) { tcs = new TaskCompletionSource<int>(state); } public TaskCompletionSourceUnit(object state, TaskCreationOptions creationOptions) { tcs = new TaskCompletionSource<int>(state, creationOptions); } public Task Task { get { return tcs.Task; } } public void SetCanceled() { tcs.SetCanceled(); } public void SetException(Exception exception) { tcs.SetException(exception); } public void SetException(IEnumerable<Exception> exceptions) { tcs.SetException(exceptions); } public void SetResult() { tcs.SetResult(0); } public bool TrySetCanceled() { return tcs.TrySetCanceled(); } public bool TrySetException(Exception exception) { return tcs.TrySetException(exception); } public bool TrySetException(IEnumerable<Exception> exceptions) { return tcs.TrySetException(exceptions); } public bool TrySetResult() { return tcs.TrySetResult(0); } } public class TaskCompletionSourceBottom { private TaskCompletionSource<int> tcs; public TaskCompletionSourceBottom() { tcs = new TaskCompletionSource<int>(); } public TaskCompletionSourceBottom(TaskCreationOptions creationOptions) { tcs = new TaskCompletionSource<int>(creationOptions); } public TaskCompletionSourceBottom(object state) { tcs = new TaskCompletionSource<int>(state); } public TaskCompletionSourceBottom(object state, TaskCreationOptions creationOptions) { tcs = new TaskCompletionSource<int>(state, creationOptions); } public Task Task { get { return tcs.Task; } } public void SetCanceled() { tcs.SetCanceled(); } public void SetException(Exception exception) { tcs.SetException(exception); } public void SetException(IEnumerable<Exception> exceptions) { tcs.SetException(exceptions); } public bool TrySetCanceled() { return tcs.TrySetCanceled(); } public bool TrySetException(Exception exception) { return tcs.TrySetException(exception); } public bool TrySetException(IEnumerable<Exception> exceptions) { return tcs.TrySetException(exceptions); } }