【问题标题】:c#-WPF: Cannot convert async lambda expression to delegate type 'Func<int>'c#-WPF:无法将异步 lambda 表达式转换为委托类型 'Func<int>'
【发布时间】:2018-05-09 05:41:20
【问题描述】:

我试图了解 Lambda 表达式如何与异步方法一起使用。

我有一个函数

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

我希望我的异步代码在 lambda 表达式中运行并从服务器取回结果。 但我得到了错误:

 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>'.

它说我只能返回一个 void、任务或任务,据我了解,我正在返回

task<int>

这是我返回的问题还是因为异步 lambda?

谢谢

编辑:

response.ResultAs<int>()

返回一个 Int 但在任务函数中,它应该作为任务返回

【问题讨论】:

  • response.ResultAs&lt;int&gt;()的类型是什么?
  • 它返回一个 int,但据我了解,当包装在 Task 中时,它不会作为 Task 返回?
  • 不,你应该返回int。比如说,你有这个代码:Func&lt;int&gt; func = () =&gt; 10; Task&lt;int&gt; task = Task.Factory.StartNew(func); task.Wait(); int result = task.Result; result 变量将是 10。我怀疑这与 ResultAs 方法有关。
  • 它可以连接,但我使用的 API 并没有写太多关于他们制作的功能。
  • 但我认为我的问题主要是因为使用异步,大多数问题似乎都来自它。

标签: c# wpf asynchronous lambda


【解决方案1】:

您的整个方法并不理想。您可以将代码重写为更简单。不过,先在现有代码上添加一些 cmets。

  1. 您正在使用Task.Factory.StartNew(),即dangerous。在 大多数情况下你应该简单地使用Task.Run()
  2. 您在访问时使用的是Task.Wait() 和Task.Result,这也是suboptimal,更不用说Task.Result includes Task.Wait()。但我想,你想测试 lambda,所以这里没问题。

ResultAs&lt;T&gt;() 方法将响应转换为 int(在您的情况下)。方法本身定义为public virtual T ResultAs&lt;T&gt;()。它不需要返回Task&lt;int&gt;,因为您的 lambda 是异步的。如果您要从 lambda 中删除 async,则必须返回 Task&lt;int&gt;,但不能通过简单地将 ResultAs&lt;T&gt; 更改为 ResultAs&lt;Task&lt;int&gt;&gt; 来做到这一点,您必须使用 @ 987654339@.

基于以上我们可以将你的方法改写成这样:

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() 创建一个新任务并返回该任务以供稍后完成。


基于 cmets,这里有两种调用 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 的基于任务的编程很陌生。我建议您阅读 Stephen Cleary 撰写的(优秀的)introduction article 并从那里继续。 async/await 的美妙之处在于,它通过您的代码自然传播,您可以编写异步代码,就像编写同步代码一样。

另外,在这里放置另一篇文章,说明为什么不应该使用 Wait() 或 Result 来简单地获取异步方法的返回值,因为这样会更好地被注意到: https://blog.stephencleary.com/2012/07/dont-block-on-async-code.html

【讨论】:

  • 如果 Server_Connect 可以成为 async 自己,那么可以完全避免很多这样的麻烦。
  • 感谢您的深入回答!我也想问一下你怎么称呼这些函数?我使用 'int test = Server_Get_Int_Async()' 调用它们,我收到从 'Task' 到 'int' 的错误。
  • 这是绝对正确的。 Task&lt;int&gt; 代表一个任务,可以现在完成,也可以在将来的任何时间完成。要获取结果对象(在您的情况下为 int),您要么需要使用 Wait()(不好!),要么也使调用方法异步。我将用一个用法示例更新答案。
【解决方案2】:

测试代码(控制台应用)。这正确显示“结果: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);
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-06-18
    • 2016-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-12-08
    相关资源
    最近更新 更多