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 54

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