错误CS0161的原因:并非所有的代码路径返回值 [英] Cause of Error CS0161: not all code paths return a value

查看:2270
本文介绍了错误CS0161的原因:并非所有的代码路径返回值的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我做了一个基本的扩展方法来重试功能添加到我的 HttpClient.PostAsync

I've made a basic extension method to add retry functionality to my 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:

错误CS0161'HttpClientExtensions.PostWithRetryAsync(HttpClient的,开放的,HttpContent,INT,动作):并非所有的代码路径返回值。

Error CS0161 'HttpClientExtensions.PostWithRetryAsync(HttpClient, Uri, HttpContent, int, Action)': not all code paths return a value.

如果我想补充抛出新的InvalidOperationException异常()末(或返回NULL 为此事),错误消失预期。我真正想知道的是:是否有被抛出,实际上退出这个方法没有或者是返回值或异常的代码路径?我无法看到它。难道我比在这种情况下,编译器的更多,或者是周围的其他方式?

If I add throw new InvalidOperationException() at the end (or return null for that matter), the error goes away as expected. 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?

推荐答案

简单的原因是,编译器必须能的静态验证的所有执行流程路径结束了一个return语句(或者一个例外)。

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

让我们来看看你的代码,它包含:

Let's look at your code, it contains:


  • 一些变量控制,而循环

  • A ,而循环,用收益语句嵌入

  • 收益语句的之后的循环

  • Some variables controlling a while loop
  • A while loop, with the return statement embedded
  • No return statement after the loop

所以基本上编译器来验证这些事情:

So basically the compiler has to verify these things:


  1. ,而循环实际执行

  2. 收益语句的总是的执行

  3. 或者的一些例外总是而是抛出。

  1. That the while loop is actually executed
  2. That the return statement is always executed
  3. Or that some exception is always thrown instead.

编译器根本无法。验证这个

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'测试()':不是所有的代码路径返回一个值

CS0161 'Test()': not all code paths return a value

因此,编译器不能推断,因为这些事实:

So the compiler is not able to deduce that because of these facts:


  • A 是一个局部变量(即只有本地代码会影响它)

  • A 有一个初始值 1 ,并且从来没有改变过

  • 如果在 A 变量大于零(这它是),在收益达到语句

  • a is a local variable (meaning that only local code can impact it)
  • a has an initial value of 1, and is never changed
  • If the a variable is greater than zero (which it is), the return statement is reached

那么代码将永远。返回值10

then the code will always return the value 10.

现在看看下面这个例子:

Now look at this example:

public int Test()
{
    const int a = 1;
    while (a > 0)
        return 10;
}



唯一不同的是我做了 A A 常量。现在它编译,但是这是因为优化器现在可以删除整个循环,最终的IL仅仅是这样的:

Only difference is that I made a 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:

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:

return 10;



所以很明显,编译器不看变量的值时,静态地分析了这些东西。实现此功能,并得到它的权利可能超过了效果还是没有这样做的缺点的成本。请记住,每个功能在孔开出了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:


  1. 它可以与异常提前退出,如果 maxAttempts 小于1

  2. 它的将会的输入,而 -loop因为尝试 1和 maxAttempts 至少为1。

  3. 如果里面的尝试<代码/ code>语句抛出一个 HttpRequestException 然后尝试递增,若仍小于或等于小于 maxAttempts ,而 -loop会做另一个循环。如果现在是不是 maxAttempts 的异常将泡沫了。

  4. 如果一些其他的异常被抛出,它不会做大的处理,并将泡出来的方法

  5. 。如果没有抛出异常,返回的响应。

  1. It can exit early with an exception if maxAttempts is less than 1
  2. It will enter the while-loop since attempt is 1 and maxAttempts is at least 1.
  3. If the code inside the 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. If it is now bigger than maxAttempts the exception will bubble up.
  4. If some other exception is thrown, it won't get handled, and will bubble out of the method
  5. If no exception is thrown, the response is returned.

所以基本上,这个代码可以说是最后总是要么抛出异常或返回,但是编译器不能静态地验证这一点。

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.

既然你已经嵌入逃生舱口(尝试与GT; maxAttempts )在两个地方,无论是作为 -loop,另外的块我会被刚刚从<$ ​​C $ C>,而<删除它简化里面的代码/ code> -loop:

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:

while (true)
{
    ...
        if (attempt > maxAttempts)
            throw;
    ...
}



既然你保证运行,而 -loop至少一次,而且它实际上是在块退出,只是说形式化和。编译器会重新快乐起来。

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.

现在流量控制是这样的:

Now the flow control looks like this:


  • ,而循环会的总是的执行(或者我们已经抛出异常)

  • ,而循环会的从不的终止(没有里面,所以没有必要在循环之后的任何代码)

  • 要退出循环,唯一可行的方法是一个显式收益或异常,无论它的编译器有验证了,因为这个特殊的错误消息的重点是标志,有可能是为了躲避方法没有明确的收益的一种方式。由于没有办法逃避偶然的检查任何更多的其余部分可以简单地跳过该方法

  • The while loop will always execute (or we have already thrown an exception)
  • The while loop will never terminate (no break inside, so no need for any code after the loop)
  • 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. Since there is no way to escape the method accidentally any more the rest of the checks can simply be skipped.

即使这种方法将编译

public int Test()
{
    while (true)
    {
    }
}


这篇关于错误CS0161的原因:并非所有的代码路径返回值的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆