Создать свой Task.Run

144
24 декабря 2018, 00:10

Каким образом в c# можно сделать async получив значение во внешний метод из лямбды?

Вот тестовый пример (он нерабочий):

    public async Task<MyOtherClass> Test(MyClass data)
    {
        return Task.Run<MyOtherClass>(() => {
            MyOtherClass result = null;
            bool endFlag = false;
            protocol.Invoke((MyOtherClass response) => // это async
            {
                endFlag = true;
                result = response;
            }, "uri/to/my/rpc", data);
            for (;;) // а это уже await
            {
                Thread.Sleep(200);
                if (endFlag)
                    break;
            }
            return result;
        });
    }

Задача функции Test - вытащить значение response из лямбды, и вернуть его, причём, сделать это надо асинхронно, к циклу for(;;) хотелось бы перйти только когда потребуется await. Подскажите, что нужно сделать, и почему этот код студия ругает?

Answer 1

Вероятно, вам надо что то вроде

public Task<MyOtherClass> Test(MyClass data)
{
    return Task.Run<MyOtherClass>(async () =>
    {
        MyOtherClass result = null;
        bool endFlag = false;
        protocol.Invoke((MyOtherClass response) => // это async
        {
            endFlag = true;
            result = response;
        }, "uri/to/my/rpc", data);
        for (; ; ) // а это уже await
        {
            await Task.Delay(200);
            if (endFlag)
                break;
        }
        return result;
    });
}

Но если вызов protocol.Invoke не блокирующий, то внутренний таск нам не нужен, у нас же уже асинхронный код.

public async Task<MyOtherClass> Test(MyClass data)
{
    MyOtherClass result = null;
    bool endFlag = false;
    protocol.Invoke((MyOtherClass response) => // это async
    {           
        result = response;
        endFlag = true; // И лучше бы флагать о конце операции в конце метода, чтобы не возникло проблем с race condition
    }, "uri/to/my/rpc", data);
    for (; ; ) // а это уже await
    {
        await Task.Delay(200);
        if (endFlag)
            break;
    }
    return result;
}

а вот уже совсем короткий вариант, что делает по сути то же самое

public Task<MyOtherClass> Test(MyClass data)
{
    var tcs = new TaskCompletionSource<MyOtherClass>(); 
    protocol.Invoke((MyOtherClass response) => // это async
    {       
        tcs.SetResult(response);
    }, "uri/to/my/rpc", data);  
    return tcs.Task;
}
READ ALSO
C# WPF Binding метода

C# WPF Binding метода

Есть метод

149
azure face api c#

azure face api c#

Как максимально просто, реализовать сравнение двух лиц на сходство используя сервис azure face

205
как копировать объект с массива

как копировать объект с массива

у меня копирует ссылку на объект не сам объект

202
Метод при скрытии игры

Метод при скрытии игры

Если на андроиде скрыть игру (любым способом) то она автоматически остановится, и возобновится при последующем открытии с того же места (если...

148