【问题标题】:Eliding async and await flow消除异步和等待流程
【发布时间】:2019-09-19 16:02:19
【问题描述】:

在关于eliding async await的文章中,有一个例子如下:

public Task<string> GetElidingKeywordsAsync(string url)
{
    using (var client = new HttpClient())
        return client.GetStringAsync(url);
}

他是这样描述流程的:

使用 GetElidingKeywordsAsync,代码会这样做:

  1. 创建 HttpClient 对象。

  2. 调用 GetStringAsync,它返回一个 未完成的任务。

  3. 释放 HttpClient 对象。

  4. 返回从 GetStringAsync 返回的任务。

为什么流程不如下?

  1. 创建 HttpClient 对象。

  2. 释放 HttpClient 对象。

  3. 调用 GetStringAsync,并返回从 GetStringAsync 返回的任务。

【问题讨论】:

  • GetStringAysn 方法一被调用就被调用,但是它还没有完成,但是由于它是aysn,我们没有等待结果,代码执行到下一行,从而处理客户端对象.异步方法在被调用时被调用,你以为你很困惑,因为你希望它只有在我们尝试从任务中获取结果时才会被调用。
  • 这篇文章可能会更有帮助,blog.stephencleary.com/2012/02/async-and-await.html
  • 您的问题不是关于 async/await 而是关于语句、它们的范围和花括号的使用。我会在标题和问题中明确说明。

标签: c# async-await


【解决方案1】:

没有花括号或分号的 using 块有一个隐含的主体:

public Task<string> GetElidingKeywordsAsync(string url)
{
    using (var client = new HttpClient())
        return client.GetStringAsync(url); // using body
}

这可以归一化为:

public Task<string> GetElidingKeywordsAsync(string url)
{
    using (var client = new HttpClient())
    {
        return client.GetStringAsync(url);
    }
}

或者用 C#8.0 更紧凑地编写:

public Task<string> GetElidingKeywordsAsync(string url)
{
    using var client = new HttpClient();
    return client.GetStringAsync(url);
}

如果您添加分号,则会出现一个空正文,从而产生您在 OP 中描述的行为:

public Task<string> GetElidingKeywordsAsync(string url)
{
    HttpClient client;
    using (client = new HttpClient());  // gets disposed before next statement
        return client.GetStringAsync(url);  // don't be fooled by the indent
}

这可以归一化为:

public Task<string> GetElidingKeywordsAsync(string url)
{
    HttpClient client;
    using (client = new HttpClient())
    {
    }
    return client.GetStringAsync(url);
}

【讨论】:

  • 在你最后的 2 个例子中 - return client.GetStringAsync(url) 中的 client 超出范围(未定义)
  • @vasily.sib 很好发现,我编辑将声明移到 using 之外
【解决方案2】:

扩展上面给出的评论,如果您了解GetStringAsync 方法的工作原理,将会有所帮助。

假设 aysnc 方法如下:

public async Task<string> GetMethodAsync(string url)
{
    // perform some operations

    // execution will pause here due to await statement 
    // after calling download URL and the Task will be returned
    var result = await DownloadURL(string);

    //perform some more function
    // finally return the result
    return result;
}

注意这里对DownloadURL的方法调用将被执行,然后只有执行会暂停等待结果返回,并返回一个task。使方法 Async 本身不会给您延迟执行,只有等待调用之后的部分被“延迟”。

这就是你会得到一个不完整的任务然后在下一步中客户被处理掉的原因。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-04-12
    • 2019-06-30
    相关资源
    最近更新 更多