将Func委托与Async方法一起使用


71

我正在尝试将Func与异步方法一起使用。我得到一个错误。

无法将异步lambda表达式转换为委托类型'Func<HttpResponseMesage>'。异步lambda表达式可能返回void,Task或Task<T>(都不能转换为)'Func<HttpResponseMesage>'

以下是我的代码:

public async Task<HttpResponseMessage> CallAsyncMethod()
{
    Console.WriteLine("Calling Youtube");
    HttpClient client = new HttpClient();
    var response = await client.GetAsync("https://www.youtube.com/watch?v=_OBlgSz8sSM");
    Console.WriteLine("Got Response from youtube");
    return response;
}

static void Main(string[] args)
{
    Program p = new Program();
    Task<HttpResponseMessage> myTask = p.CallAsyncMethod();
    Func<HttpResponseMessage> myFun =async () => await myTask;
    Console.ReadLine();
}

3
我有一篇关于异步委托类型的博客文章,您可能会有所帮助。
史蒂芬·克利西

Answers:


103

正如错误说,异步方法返回TaskTask<T>void。因此,要使其正常工作,您可以:

Func<Task<HttpResponseMessage>> myFun = async () => await myTask;

3
请注意,异步操作可能在用户按下按键并完成操作时尚未Console.ReadLine()完成。该应用可能会在异步操作完成之前终止,除非您Wait在上明确指定Task
Johnathon Sullinger

4

我通常采取的路径是有Main方法调用一个Run()方法,返回任务,并.Wait()Task完成。

class Program
{
    public static async Task<HttpResponseMessage> CallAsyncMethod()
    {
        Console.WriteLine("Calling Youtube");
        HttpClient client = new HttpClient();
        var response = await client.GetAsync("https://www.youtube.com/watch?v=_OBlgSz8sSM");
        Console.WriteLine("Got Response from youtube");
        return response;
    }

    private static async Task Run()
    {
        HttpResponseMessage response = await CallAsyncMethod();
        Console.ReadLine();
    }

    static void Main(string[] args)
    {
        Run().Wait();
    }
}

这样,您的控制台应用程序的其余部分就可以在完全异步/等待支持下运行。由于控制台应用程序中没有任何UI线程,因此使用不会造成死锁的风险.Wait()


1
这将使用Wait()阻止Task,并且它不再是执行异步上下文的正确方法。请在这里
-Pimenta,

3
您提供的链接是针对MVC应用的,您将在此处正确。在C#7.2之前,这是您必须在控制台应用程序中执行的操作,否则控制台应用程序将在异步操作完成之前完成执行并关闭。在控制台应用程序中无需担心任何SyncContext。但是,C#7.2允许您的Main方法返回一个异步Task,以便您可以在控制台应用程序中等待。
Johnathon Sullinger

3

代码修复,例如:

static void Main(string[] args)
        {
            Program p = new Program();
            Task<HttpResponseMessage> myTask = p.CallAsyncMethod();
            Func<Task<HttpResponseMessage>> myFun = async () => await myTask;
            Console.ReadLine();
        }

-1

在Func内部运行任务,等待它并检查异常,然后返回结果。

Func<HttpResponseMessage> myFun = () => 
{
   var t = Task.Run(async () => await myTask);
   t.Wait();
   if (t.IsFaulted)
      throw t.Exception;
   return t.Result;
};

为什么这被否决?我正在尝试学习异步编程,这确实可以帮助我了解这一点。
埃里克

1
@Eric-因为它使用Task.Run()机制,从技术上讲不是“异步”的。它更像是并行/并发构造。关于异步与并行的一般共识是:异步-> I / O操作(认为数据库,磁盘等访问)并行-> CPU密集型任务,例如在大型int上进行斐波那契计算
-bbqchickenrobot

很有帮助。我正在执行高性能计算,但一直找不到好的模式,这可能是因为我一直在寻找异步而不是并行计算。
埃里克
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.