Лучший способ преобразовать асинхронный метод на основе обратного вызова в ожидаемую задачу


каков был бы лучший способ преобразовать/обернуть "классический" асинхронный метод, который использует обратный вызов к чему-то, что возвращает (ожидаемую) задачу?

например, учитывая следующий метод:

public void GetStringFromUrl(string url, Action<string> onCompleted);

единственный способ, который я знаю, чтобы обернуть это в метод, возвращающий задачу:

public Task<string> GetStringFromUrl(string url)
{
     var t = new TaskCompletionSource<string>();

     GetStringFromUrl(url, s => t.TrySetResult(s));

     return t.Task;
}

это единственный способ сделать это?

и есть ли способ обернуть вызов GetStringFromUrl( url, обратный вызов) в самой задаче (т. е. вызов сам будет работать внутри задачи, а не синхронно)

2 59

2 ответа:

ваш код короткий, читаемый и эффективный, поэтому я не понимаю, почему вы ищете альтернативы, но я ничего не могу придумать. Я думаю, что ваш подход является разумным.

Я также не уверен, почему вы думаете, что синхронная часть в порядке в оригинальной версии, но вы хотите избежать этого в Taskна основе одного. Если вы считаете, что синхронная часть может занять слишком много времени, исправьте ее для обеих версий метода.

но если вы хотите запустить его асинхронно (т. е. на ThreadPool) только в Task версия, вы можете использовать Task.Run():

public Task<string> GetStringFromUrl(string url)
{
    return Task.Run(() =>
    {
        var t = new TaskCompletionSource<string>();

        GetStringFromUrl(url, s => t.TrySetResult(s));

        return t.Task;
    });
}

ваша предполагаемая реализация отлично подходит для этого, предполагая, что обратный вызов только когда-либо обрабатывает успешные ситуации. Что в настоящее время происходит, если исключение происходит в асинхронных основаниях реализации GetStringFromUrl? Нет никакого реального способа для них распространить это на обратный вызов действия... они просто проглатывают его и возвращают вам нуль или что-то еще?

единственное, что я бы рекомендовал, это использовать следующее новое соглашение об именовании таких асинхронных методов с помощью суффикс XXXAsync.