c # -WPF: невозможно преобразовать асинхронное лямбда-выражение в тип делегата 'Func <int>' - PullRequest
0 голосов
/ 06 мая 2018

Я пытаюсь понять, как работает лямбда-выражение с асинхронными методами.

У меня есть функция

private int Server_Get_Int(){
            Task<int> task = Task.Factory.StartNew<int>( async () => {
                FirebaseClient c = Server_Connect();
                FirebaseResponse response = await c.GetAsync("todos/set");
                return response.ResultAs<int>(); //The response will contain the data being retreived
            } );
            task.Wait();
            int result = task.Result;
            Console.WriteLine(result);
            return result;
        }

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

 error CS4010: Cannot convert async lambda expression to delegate type 'Func<int>'. An async lambda expression may return void, Task or Task<T>, none of which are convertible to 'Func<int>'.

В нем говорится, что я могу вернуть только пустоту, задание или задание <>, и, насколько я понимаю, я возвращаю

task<int>

Это проблема с тем, что я возвращаю, или это из-за асинхронной лямбды?

Спасибо

Edit:

response.ResultAs<int>()

Возвращает Int, но, находясь внутри функции Task, оно должно быть возвращено как Task

Ответы [ 2 ]

0 голосов
/ 06 мая 2018

Весь ваш метод неоптимален. Вы могли бы переписать свой код, чтобы быть намного проще. Однако сначала несколько комментариев к существующему коду.

  1. Вы используете Task.Factory.StartNew(), что опасно . В В большинстве случаев вы должны просто использовать Task.Run()
  2. Вы используете Task.Wait() и Task.Result, что также неоптимально , не говоря уже о том, что Task.Result включает Task.Wait() при доступе к нему. Но я думаю, что вы хотите проверить лямбду, так что здесь все в порядке.

Метод ResultAs<T>() преобразует ответ в int (в вашем случае). Сам метод определяется как public virtual T ResultAs<T>(). Не нужно возвращать Task<int>, потому что ваша лямбда асинхронна. Если вы удалите async из лямбды, вам нужно будет вернуть Task<int>, но вы не сможете сделать это, просто изменив ResultAs<T> на ResultAs<Task<int>>, вам придется использовать TaskCompletionSource.

Исходя из вышеизложенного, мы можем переписать ваш метод следующим образом:

private int Server_Get_Int(){
    var task = Task.Run(async () => {
        var c = Server_Connect();
        return (await c.GetAsync("todos/set")).ResultAs<int>();
    });

    int result = task.Result;
    Console.WriteLine(result);
    return result;
}

Более краткий подход может выглядеть так:

private async Task<int> Server_Get_Int_Async(){
    return await Task.Run(async () => {
        var c = Server_Connect();
        return (await c.GetAsync("todos/set")).ResultAs<int>();
    });
}

Это создает новую задачу с помощью Task.Run() и возвращает ее для выполнения позже.


На основе комментариев здесь приведены два способа вызова метода Server_Get_Int_Asnyc(). Я использовал явные типы, чтобы вы могли следить за моим комментарием, но почти в любом случае лучше использовать var, потому что компилятор может выбрать лучший тип для задания.

public async Task Foo()
{
    // This is the fetch task that's going to be completed sometime in the future. You should almost in any case use configure await on your tasks. For reasons see below.
    Task<int> intTask = Server_Get_Int_Async().ConfigureAwait(false);

    // Do something other with the task object

    // Finally await it and print
    int result = await intTask;
    Console.WriteLine(result);
}


// Do this if you just need the result and nothing else.
public async Task Bar() 
{
    int result = await Server_Get_Int_Async().ConfigureAwait(false);

   Console.WriteLine(result);
}

В конце концов, вы, кажется, довольно плохо знакомы с программированием на основе задач с помощью async / await. Я рекомендую вам прочитать (превосходно) вступительную статью , написанную Стивеном Клири, и продолжить. Прелесть async / await в том, что он распространяется естественным образом через ваш код, и вы можете писать асинхронный код почти так же, как если бы вы писали синхронный код.

Кроме того, разместив здесь еще одну статью о том, почему вы не должны использовать Wait() или Result, чтобы просто получить возвращаемое значение асинхронного метода, поскольку это будет заметно лучше: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

0 голосов
/ 06 мая 2018

Тестовый код (консольное приложение). Это правильно показывает «Результат: 10».

static void Main(string[] args)
{

    Func<Task<int>> func = async () => { await Task.Delay(1000); return 10; };
    var task = Task.Factory.StartNew(func);
    task.Wait();
    int result = task.Unwrap().Result;
    WriteLine($"Result: {result}");
    ReadKey(true);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...