【问题标题】:How to include a multiline block of code in a lambda expression for Polly ExecuteAsync?如何在 Polly ExecuteAsync 的 lambda 表达式中包含多行代码块?
【发布时间】:2025-12-24 23:20:08
【问题描述】:

我的工作代码使用 Polly 策略 (IAsyncPolicy<HttpResponseMessage>) 上的 ExecuteAsync() 方法从网页中提取数据。我想向它添加一些调试日志记录,但到目前为止,我无法弄清楚发生这种情况的正确语法,除非我将日志记录和 http 调用包装在一个单独的方法中,然后通过 @987654327 调用它@。

这对我来说似乎并不“正确”,我觉得有一种更清洁或更直接的方法。我认为我的问题是我对 Func<T> 和 lambda 表达式如何真正操作来实现这一点没有足够的了解,因为当我将内容包装在 {} 中时,我会遇到如下错误:

并非所有代码路径都返回 Func<CancellationToken, Task<HttpResponseMessage>> 类型的 lambda 表达式中的值。

这是我原来的工作代码:

var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];

result = await retryPolicy.ExecuteAsync(
    async cancellationToken =>    
        await httpClient.GetAsync(myUrl, cancellationToken)
    , cancellationToken
);

此代码会产生“并非所有代码路径都在 Func&lt;CancellationToken, Task&gt; 类型的 lambda 表达式中返回值错误:

var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];

result = await retryPolicy.ExecuteAsync(
    async cancellationToken =>    
    {
        await httpClient.GetAsync(myUrl, cancellationToken);
    }
    , cancellationToken
);

这是我的“hack”,可以通过额外的方法完成我想要的:

private async Task<HttpResponseMessage> TestWithLogAsync(HttpClient httpClient, string myUrl, CancellationToken cancellationToken)
{
    _logger.LogDebug("Requesting from: {myUrl}", myUrl);
    var result = await httpClient.GetAsync(myUrl, cancellationToken);
    return result;
}

var httpClient = _httpClientFactory.CreateClient();
HttpResponseMessage result;
var retryPolicy = (IAsyncPolicy<HttpResponseMessage>)_policyRegistry[RetryPolicyKeyName];

result = await retryPolicy.ExecuteAsync(
    async cancellationToken =>
        await TestWithLogAsync(httpClient, myUrl, cancellationToken)
    , cancellationToken
);

【问题讨论】:

  • 这是你想要的吗? Can a C# lambda expression have more than one statement?。如果不能,您可以edit 您的问题来分享生成 Not all code paths return a value in lambda expression of type 'Func&lt;CancellationToken, Task&gt; 错误的代码吗?
  • 在发布此链接之前,我已经查看了该链接,但我相信我仍然遗漏了一些东西。也许是因为我将 cancelToken 变量作为输入传递给我的 lambda?我最初提交的内容中缺少这一行,但我现在添加了它。谢谢你的评论。我已经按照建议包含了错误生成代码。
  • @RyanKayser 考虑过使用Typed Client with resilient policies?通过这种方法,可以注入自定义 DelegatingHandler 来记录所有内容。

标签: c# lambda polly


【解决方案1】:

你有什么:

result = await retryPolicy.ExecuteAsync(
    await httpClient.GetAsync(managementUrl, cancellationToken)
    , cancellationToken
);

相当于:

result = await retryPolicy.ExecuteAsync(async () => {
      return await httpClient.GetAsync(managementUrl, cancellationToken);
    }
    , cancellationToken
);

因此这将在 lambda 中执行多行:

result = await retryPolicy.ExecuteAsync(async () => {
      _logger.LogDebug("Requesting from: {managementUrl}", managementUrl);
      return await httpClient.GetAsync(managementUrl, cancellationToken);
    }
    , cancellationToken
);

..虽然我不太清楚managementUrl 在您的示例中如何变成myUrl,以及它们是否不同.. 我假设不是

【讨论】:

  • 你是对的,managementUrl 和 myUrl 没有区别。我已经更新了代码以保持一致。我还错误地粘贴了我的原始代码并忽略了包含以下行: async cancelToken => 当我按照您的建议包含 {} 时,我在 => 下收到带有红色波浪的此错误:“并非所有代码路径都返回'Func' 类型的 lambda 表达式中的值。
  • 你确定你复制了所写的代码吗?我的建议肯定是return - 你错过了吗?
  • 这对我有帮助。您的示例中没有我的附加取消令牌,但它有()。我所做的是在其中添加带有cancellationToken的(),如下所示:``` async (cancellationToken) => ``` 一切正常。我很想更好地了解发生了什么。为什么我运行单个语句时没有()可以工作,但我使用块时需要()?谢谢你的帮助!我将此标记为答案。
最近更新 更多