为什么编译器会抱怨 'not all code paths return a value' 而我可以清楚地看到他们这样做?

Why does the compiler complain that 'not all code paths return a value' when I can clearly see that they do?

我正在尝试弄清楚为什么编译器对这个函数有问题。它给了我 "Not all code paths return a value" 错误,但是我看不到控制流会传递给 if( a ) 表达式而 a 不为真的情况(所以 if( a ) 是多余的,但编译器似乎无法识别)。

public static Boolean Foo(Boolean x)
{
    Boolean a = false;
    if( x )
    {
        a = true;
    }
    else
    {
        try
        {
            SomethingThatMightThrow();
            Assert.IsFalse( a );
            return a;
        }
        catch(Exception)
        {
            a = true;
        }
    }

    if( a )
    {
        return x;
    }
}

直接的解决方法是完全删除 if( a ) guard 语句并立即删除 return x - 但为什么编译器会抱怨,即使它应该能够静态证明所有可能的代码路径都将命中 return 语句?至关重要的是,没有循环,这通常是它无法证明 return-ness 的主要原因。

我正在使用 VS2015 更新 3。

我认为编译器对代码进行了非常简单的分析,因此必须明确给出 return。

这可能看起来像是一个错误的决定,但在处理复杂代码时,returned 值可能不清楚。于是,程序员被迫return了。

您的示例可以像这样减少到最低限度:

public static Int32 Main(String[] args)
{
    var printUsage = true;
    if (printUsage)
    {
        return 0;
    }

    // return nothing, so compiler is not happy
}

同时仍然出现错误。

注意:如果您使用 Resharper,它将执行您想要的分析并相应地警告您:

if (printUsage)         // Warning: expression is always true 

当您到达函数末尾时,afalse 受支持的场景。这种情况是当您调试代码并使用调试器将 set a 设置为 false.

C# 编译器规则设计简单。在 C# 借用的语言中,函数问题可能不会 returning 任何东西是编译器警告无法涵盖的问题。误报太多,因此警告被调整为只警告明显的情况,引入误报。 C# 的规则是一种妥协,如果熟悉规则的人可以理解误报,那么误报是可以接受的,而误报是不可接受的。您可以保证,如果您的函数的代码路径没有 return 值,编译器会检测到它。

这些简单规则的一部分是不考虑变量的值。即使 a 静态地保证为 true,编译器在设计上也无法利用这一事实。

@PetSerAl已经引用了C#语言规范中的相关写法:

8.1 End points and reachability

[...]

To determine whether a particular statement or end point is reachable, the compiler performs flow analysis according to the reachability rules defined for each statement. The flow analysis takes into account the values of constant expressions (§7.19) that control the behavior of statements, but the possible values of non-constant expressions are not considered. In other words, for purposes of control flow analysis, a non-constant expression of a given type is considered to have any possible value of that type.

这是当前发布的最新语言规范的一部分,即针对 C# 5.0 的规范。您正在使用的版本 C# 6.0(这是 VS2015 提供的)尚未发布规范,因此措辞可能会略有不同,但正如您的编译器所显示的那样,实际上相同的规则仍然适用。

是run-time对compile-time

你的例子太复杂了。这也不会编译:

static int Test()
{
    bool f = true;
    if (f)
    {
        return 1;
    }
    else
    {
        //Not all code paths return a value
    }
}

另一方面,这将:

static int Test()
{
    if (true)
    {
        return 1;
    }
    else
    {
        //No error
    }
}

我猜测无论采用何种验证机制都没有足够的逻辑来推断 run-time 变量的内容。 Compile-time变量没问题。