Non-Generic TaskCompletionSource или альтернатива
Я работаю с окном оповещения (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 ответов:
метод может быть изменен на:
public Task ShowAlert(object message, string windowTitle)
Task<bool>
наследует отTask
Так что вы можете вернутьсяTask<bool>
пока только разоблачивTask
абонентуEdit:
я нашел документ Microsoft,http://www.microsoft.com/en-us/download/details.aspx?id=19957, Стивен Тоуб под названием "асинхронный шаблон на основе задач", и он имеет следующий отрывок, который рекомендует этот же шаблон.
не существует универсального аналога TaskCompletionSource
. Тем не менее, задачу вытекает из задач, и, таким образом, общий TaskCompletionSource может использоваться для ввода-вывода методов, которые просто возвращают задач с использованием источника с манекеном становится TResult (логический является хорошим по умолчанию, и если разработчик заботится о потребителе задачи приведения типов его задачу , частный типу TResult могут быть использованы)
Если вы не хотите утечки информации, общий подход заключается в использовании
TaskCompletionSource<object>
и в результатеnull
. Тогда просто верните его какTask
.
Нито.AsyncEx реализует не общий
TaskCompletionSource
класс, кредит г-ну @ StephenCleary выше.
От @Kevin Kalitowski
Я нашел документ 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; }
сначала я подумал, что это не очень хорошо, потому что вы не можете напрямую добавить модификатор" 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; }
Edit: сначала я думал, что я получил через горб. Но, когда я запустил эквивалентный код в своем приложении, этот код просто заставляет приложение зависать, когда оно ожидает tcs.Задача.; Итак, я все еще считаю, что это серьезный недостаток дизайна в синтаксисе async/await c#.
есть на самом деле две версии "non-generic"
TaskCompletionSource
для реализации. С гипотетическим именем типа, они могут быть поняты какTaskCompletionSource<Unit>
иTaskCompletionSource<Bottom>
.разница между ними заключается в том, что первый должен определить a
SetResult
без параметра, и более поздно не определитSetResult
на всех. Это сделаетTask
наTaskCompletionSource<Bottom>
невозможно выполнить нормально, но вы можете отменить или установить его в какой-то момент.оба варианта имеют свое использование случаи, но я думаю, что Microsoft не приняла решение стандартизировать ни один из них.
вот пример реализации
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); } }