[英]Cause of Error CS0161: not all code paths return a value
I've made a basic extension method to add retry functionality to my HttpClient.PostAsync
:我做了一个基本的扩展方法来向我的
HttpClient.PostAsync
添加重试功能:
public static async Task<HttpResponseMessage> PostWithRetryAsync(this HttpClient httpClient, Uri uri, HttpContent content, int maxAttempts, Action<int> logRetry)
{
if (maxAttempts < 1)
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "Max number of attempts cannot be less than 1.");
var attempt = 1;
while (attempt <= maxAttempts)
{
if (attempt > 1)
logRetry(attempt);
try
{
var response = await httpClient.PostAsync(uri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
catch (HttpRequestException)
{
++attempt;
if (attempt > maxAttempts)
throw;
}
}
}
The above code gives me the following error:上面的代码给了我以下错误:
Error CS0161 'HttpClientExtensions.PostWithRetryAsync(HttpClient, Uri, HttpContent, int, Action)': not all code paths return a value.
错误 CS0161 'HttpClientExtensions.PostWithRetryAsync(HttpClient, Uri, HttpContent, int, Action)':并非所有代码路径都返回值。
If I add throw new InvalidOperationException()
at the end (or return null
for that matter), the error goes away as expected.如果我在末尾添加
throw new InvalidOperationException()
(或return null
),则错误会按预期消失。 What I'd really like to know is: is there any code path that actually exits this method without either a value being returned or an exception being thrown?我真正想知道的是:是否有任何代码路径实际退出此方法而没有返回值或抛出异常? I can't see it.
我看不到它。 Do I know more than the compiler in this case, or is it the other way around?
在这种情况下,我是否比编译器了解更多,还是相反?
The simple reason is that the compiler has to be able to statically verify that all execution flow paths end up with a return statement (or an exception). 原因很简单,编译器必须能够静态验证所有执行流路径是否以return语句(或异常)结尾。
Let's look at your code, it contains: 让我们看看您的代码,其中包含:
while
loop while
循环的变量 while
loop, with the return
statement embedded while
循环,嵌入return
语句 return
statement after the loop return
语句 So basically the compiler has to verify these things: 因此,基本上,编译器必须验证以下内容:
while
loop is actually executed while
循环 return
statement is always executed return
语句 The compiler is simply not able to verify this. 编译器根本无法验证这一点。
Let's try a very simple example: 让我们尝试一个非常简单的示例:
public int Test()
{
int a = 1;
while (a > 0)
return 10;
}
This trivial example will generate the exact same error: 这个简单的示例将产生完全相同的错误:
CS0161 'Test()': not all code paths return a value
CS0161'Test()':并非所有代码路径都返回一个值
So the compiler is not able to deduce that because of these facts: 因此,由于以下事实,编译器无法推断出这一点:
a
is a local variable (meaning that only local code can impact it) a
是局部变量(意味着只有局部代码可以影响它) a
has an initial value of 1
, and is never changed a
的初始值为1
,并且永远不变 a
variable is greater than zero (which it is), the return
statement is reached a
变量大于零(是),则return
语句 then the code will always return the value 10. 那么代码将始终返回值10。
Now look at this example: 现在看这个例子:
public int Test()
{
const int a = 1;
while (a > 0)
return 10;
}
Only difference is that I made a
a const
. 唯一的不同是,我做
a
一个const
。 Now it compiles, but this is because the optimizer is now able to remove the whole loop, the final IL is just this: 现在可以编译了,但这是因为优化器现在可以删除整个循环,最终的IL就是这样:
Test:
IL_0000: ldc.i4.s 0A
IL_0002: ret
The whole while
loop and local variable is gone, all is left is just this: 整个
while
循环和局部变量都消失了,剩下的就是这个:
return 10;
So clearly the compiler does not look at variable values when it statically analyzes these things. 因此很明显,编译器在静态分析这些内容时不会查看变量值。 The cost of implementing this feature and getting it right probably outweighs the effect or the downside of not doing it.
实施并正确实现此功能的成本可能会超过不执行此操作所带来的影响或负面影响。 Remember that "Every feature starts out in the hole by 100 points, which means that it has to have a significant net positive effect on the overall package for it to make it into the language."
请记住, “每个功能在漏洞中的起点都是100点,这意味着它必须对整个程序包产生显着的净积极影响,才能使其成为语言。” .
。
So yes, this is definitely a case where you know more about the code than the compiler. 所以是的,这绝对是您比编译器更了解代码的情况。
Just for completeness, let's look at all the ways your code can flow: 为了完整起见,让我们看一下代码可以流动的所有方式:
maxAttempts
is less than 1 maxAttempts
小于1,它可能会提早退出,并发生异常 while
-loop since attempt
is 1 and maxAttempts
is at least 1. while
因为-loop attempt
为1, maxAttempts
至少为1。 try
statement throws a HttpRequestException
then attempt
is incremented and if still less than or equal to maxAttempts
the while
-loop will do another iteration. try
语句抛出一个HttpRequestException
然后attempt
递增,如果仍然小于或等于maxAttempts
的while
-loop会做另一次迭代。 If it is now bigger than maxAttempts
the exception will bubble up. maxAttempts
则异常将冒泡。 So basically, this code can be said to always end up either throwing an exception or return, but the compiler is not able to statically verify this. 因此,基本上可以说,此代码总是以抛出异常或返回为最终结果,但是编译器无法静态验证此结果。
Since you have embedded the escape hatch ( attempt > maxAttempts
) in two places, both as a criteria for the while
-loop, and additionally inside the catch
block I would simplify the code by just removing it from the while
-loop: 由于您已将转义
attempt > maxAttempts
填充( attempt > maxAttempts
)嵌入了两个位置,均作为while
-loop的标准,另外还包含在catch
块内,因此我只需将其从while
-loop中删除即可简化代码:
while (true)
{
...
if (attempt > maxAttempts)
throw;
...
}
Since you're guaranteed to run the while
-loop at least once, and that it will actually be the catch
block that exits it, just formalize that and the compiler will again be happy. 由于可以确保至少运行一次
while
-loop,并且实际上它是退出该循环的catch
块,因此只需对其进行形式化,编译器将再次感到满意。
Now the flow control looks like this: 现在,流控制如下所示:
while
loop will always execute (or we have already thrown an exception) while
循环将始终执行(或者我们已经引发了异常) while
loop will never terminate (no break
inside, so no need for any code after the loop) while
循环永远不会终止(内部不会break
,因此循环后不需要任何代码) The only possible way to exit the loop is either an explicit return
or an exception, neither of which the compiler has to verify any more because the focus of this particular error message is to flag that there is potentially a way to escape the method without an explicit return
. 退出循环的唯一可能方法是显式
return
或异常,编译器都不必再进行验证,因为此特定错误消息的重点是标记出存在一种可能的方法,而无需明确的return
。 Since there is no way to escape the method accidentally any more the rest of the checks can simply be skipped. 由于无法避免方法的意外退出,因此可以简单地跳过其余检查。
Even this method will compile: 即使此方法也可以编译:
public int Test() { while (true) { } }
如果抛出HttpRequestException并执行catch块,则可能会根据条件(attempt> maxAttempts)跳过throw语句,以使路径不会返回任何内容。
As Error states that not all code paths return a value
you are not returning value for each code path 由于错误指出
not all code paths return a value
您并不是为每个代码路径都返回值
You must throw a exception or return value
您必须抛出异常或返回值
catch (HttpRequestException)
{
++attempt;
if (attempt > maxAttempts)
throw;
else
return null;//you must return something for this code path
}
you could modify your code so that all code path returns value. 您可以修改代码,以便所有代码路径都返回值。 code should be something like this
代码应该是这样的
public static async Task<HttpResponseMessage> PostWithRetryAsync(this HttpClient httpClient, Uri uri, HttpContent content, int maxAttempts, Action<int> logRetry)
{
HttpResponseMessage response = null;
if (maxAttempts < 1)
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "Max number of attempts cannot be less than 1.");
var attempt = 1;
while (attempt <= maxAttempts)
{
if (attempt > 1)
logRetry(attempt);
try
{
response = await httpClient.PostAsync(uri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
}
catch (HttpRequestException)
{
++attempt;
if (attempt > maxAttempts)
throw;
}
}
return response;
}
public static async Task<HttpResponseMessage> PostWithRetryAsync(this HttpClient httpClient, Uri uri, HttpContent content, int maxAttempts, Action<int> logRetry)
{
if (maxAttempts < 1)
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "Max number of attempts cannot be less than 1.");
var attempt = 1;
while (attempt <= maxAttempts)
{
if (attempt > 1)
logRetry(attempt);
try
{
var response = await httpClient.PostAsync(uri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
catch (HttpRequestException)
{
++attempt;
if (attempt > maxAttempts)
throw;
else
return something; // HERE YOU NEED TO RETURN SOMETHING
}
}
}
but in case you want to continue to loop, you need to return at the end: 但是如果您想继续循环,则需要最后返回:
public static async Task<HttpResponseMessage> PostWithRetryAsync(this HttpClient httpClient, Uri uri, HttpContent content, int maxAttempts, Action<int> logRetry)
{
if (maxAttempts < 1)
throw new ArgumentOutOfRangeException(nameof(maxAttempts), "Max number of attempts cannot be less than 1.");
var attempt = 1;
while (attempt <= maxAttempts)
{
if (attempt > 1)
logRetry(attempt);
try
{
var response = await httpClient.PostAsync(uri, content).ConfigureAwait(false);
response.EnsureSuccessStatusCode();
return response;
}
catch (HttpRequestException)
{
++attempt;
if (attempt > maxAttempts)
throw;
}
}
return something; // HERE YOU NEED TO RETURN SOMETHING
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.