我试图找出编译器为什么有这个功能的问题.它给了我"并非所有代码路径返回值"错误,但是我看不到控制流将传递给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
.
我正在使用VS2015 Update 3.
还有人支持的方案a
是false
,当你达到你的函数的末尾.那种情况是您调试代码并使用调试器设置 a
为false
.
C#编译器规则设计简单.在C#借用的语言中,函数可能无法返回任何内容的问题是编译器警告无法解决的问题.有太多的误报,因此警告被调整为仅警告明显的案例,引入假阴性.C#的规则是一种妥协,如果对于熟悉规则的人来说,误报是可以接受的,并且假阴性是不可接受的.您可以保证,如果您的函数具有不返回值的代码路径,编译器会检测到它.
这些简单规则的一部分是不考虑变量的值.即使a
是静态保证true
,编译器也不能利用这个事实.
@PetSerAl已经引用了C#语言规范中的相关措辞:
8.1终点和可达性
[...]
要确定特定语句或端点是否可访问,编译器将根据为每个语句定义的可访问性规则执行流分析.流分析考虑了控制语句行为的常量表达式(第7.19节)的值,但不考虑非常量表达式的可能值.换句话说,出于控制流分析的目的,给定类型的非常量表达式被认为具有该类型的任何可能值.
这是最新发布的语言规范的一部分,即C#5.0.您正在使用的版本,C#6.0(VS2015提供的版本),还没有已发布的规范,因此措辞可能略有不同,但正如您的编译器所示,实际上相同的规则仍然适用.
它是运行时与编译时
你的例子太复杂了.这也不会编译:
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 } }
我猜测无论有什么验证机制都没有足够的逻辑来推断运行时变量的内容.编译时变量没问题.
我认为编译器对代码进行了非常简单的分析,因此必须明确给出返回.
这看起来可能是错误的决定,但在处理复杂代码时,返回的值可能不明确.所以,程序员被迫返回它.
您的示例可以减少到最小,如下所示:
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