Использование C# Задача для операции asyn c. - PullRequest
0 голосов
/ 10 февраля 2020

Предположим, у меня есть объект SomeObj, который выполняет асинхронную операцию, которую он реализовал как событие, возвращающее часть данных.

У меня может быть код, который выглядит следующим образом:

private void MyFunc1(Func<int> callback)
{
    SomeObj obj = SomeObj.GetSomeObj();
    obj.onAsyncComplete += callback;
}

Таким образом, в этой реализации обратный вызов используется для асинхронного приема результирующих данных (int), возвращаемых SomeObj.onAsyncComplete.

Я бы хотел переместить этот гипотетический пример к использованию async и await:

private async int MyFunc1()
{
    SomeObj obj = SomeObj.GetSomeObj();
    Task<int> asyncCompleteTask = /* something with obj.onAsyncComplete */
    await asyncCompleteTask;
    return asyncCompleteTask.Result;
}

Как бы я совершил sh что-то подобное? Цель состоит в том, чтобы иметь возможность await получить int результат, пройденный событием onAsyncComplete. Предположим, что SomeObj нельзя изменить.

1 Ответ

3 голосов
/ 10 февраля 2020

Для большей наглядности ссылки BART: https://docs.microsoft.com/en-us/dotnet/standard/asynchronous-programming-patterns/interop-with-other-asynchronous-patterns-and-types#tasks -and-the-event-based-asynchronous-pattern-eap

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

Ваш MyFunc1 может выглядеть так это:

public Task<int> MyFunc1()
{
    SomeObj someObj = new SomeObj();
    TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
    someObj.OnAsynComplete += (r) => tcs.SetResult(r);
    someObj.GetSomeObj();
    return tcs.Task;
}

Или вы можете сделать что-то с расширением:

public static class SomeObjExtension
{
    public static Task<int> GetResultAsyncTask(this SomeObj someObj)
    {
        TaskCompletionSource<int> tcs = new TaskCompletionSource<int>();
        someObj.OnAsynComplete += (r) => tcs.SetResult(r);
        someObj.GetSomeObj();
        return tcs.Task;
    }
}


async void Main()
{
    SomeObj someObj = new SomeObj();
    int result = await someObj.GetResultAsyncTask();
    Console.WriteLine($"Got some number back: {result}");
}

Если вы запускаете его без расширения, оно следует указанному вами шаблону:

void Main()
{
    SomeObj someObj = new SomeObj();
    someObj.OnAsynComplete += (r) => Console.WriteLine($"Got some number back: {r}");
    someObj.GetSomeObj();
}

Для тестирования я создал SomeObj так:

public class SomeObj
{
    public void GetSomeObj()
    {
        Task.Run(async () => 
        {
            //do something...
            await Task.Delay(5000);
            OnAsynComplete?.Invoke(new Random().Next(1, 10000));
        });
    }
    public event OnAsyncCompleteHandler OnAsynComplete;
    public delegate void OnAsyncCompleteHandler(int result);
}
...