为什么可以';C#编译器不会告诉你这个函数总是返回或抛出吗?
我有以下(简化的)方法: 我似乎很清楚,这个方法要么返回要么抛出。然而,C#编译器向我抱怨说,为什么可以';C#编译器不会告诉你这个函数总是返回或抛出吗?,c#,exception,for-loop,code-analysis,C#,Exception,For Loop,Code Analysis,我有以下(简化的)方法: 我似乎很清楚,这个方法要么返回要么抛出。然而,C#编译器向我抱怨说,并不是所有的代码路径都返回值 这是C#编译器代码分析的一个限制吗 或者是否存在某种情况,我看不到for循环可以在没有抛出或返回的情况下完成 编译器不知道for循环至少会执行一次。它认为它是一个有效的选项,它从不运行,在这种情况下,它不会抛出或返回 虽然通过对您的程序进行足够复杂的分析,理论上可以证明它总是返回或抛出,但这种分析非常复杂,而且需要大量的性能。C编译器编译器不想冒错误的风险,或者考虑编译的
并不是所有的代码路径都返回值
- 这是C#编译器代码分析的一个限制吗
- 或者是否存在某种情况,我看不到
for
循环可以在没有抛出或返回的情况下完成
编译器不知道for循环至少会执行一次。它认为它是一个有效的选项,它从不运行,在这种情况下,它不会抛出
或返回
虽然通过对您的程序进行足够复杂的分析,理论上可以证明它总是返回或抛出,但这种分析非常复杂,而且需要大量的性能。C编译器编译器不想冒错误的风险,或者考虑编译的时间大大增加,以便增加这种复杂的分析。他们选择使用“可访问”与“不可访问”代码的更简单定义,这样实现起来更容易、更快
至于实际的修复,只需在方法的最后添加一个throw
,并可能添加一条注释,说明实际上不可能命中它。编译器不知道for循环至少会执行一次。它认为它是一个有效的选项,它从不运行,在这种情况下,它不会抛出
或返回
虽然通过对您的程序进行足够复杂的分析,理论上可以证明它总是返回或抛出,但这种分析非常复杂,而且需要大量的性能。C编译器编译器不想冒错误的风险,或者考虑编译的时间大大增加,以便增加这种复杂的分析。他们选择使用“可访问”与“不可访问”代码的更简单定义,这样实现起来更容易、更快
至于实际的修复,只需在方法的最后添加一个throw
,并可能添加一条注释,说明实际上不可能命中它
为什么C#编译器不能告诉这个函数总是返回或抛出
编译器不会试图模拟程序的工作方式来查看可以执行哪些分支。它只是查看所有可能的分支。在您的情况下,如果出于某种原因,remaingtrys>=0
计算为false,那么它将从方法末尾脱落,而不返回布尔值或抛出值
您可以通过删除for
循环中的复选框来修复它:
public bool DoWorkWithRetry()
{
for (int remainingTries = Constants.MaxRetries;; remainingTries--)
{
// etc...
}
}
那张支票没有任何用处
您还可以重写方法以完全避免问题:
for (int remainingTries = Constants.MaxRetries; remainingTries >= 0; remainingTries--)
{
try
{
return DoWork();
}
catch (Exception ex)
{
// fall through to retry
}
}
throw new WorkException(
String.Format("Failed after {0} retries.", Constants.MaxRetries),
ex);
也请不要抓住和吞下所有的例外。捕获您知道的特定异常。捕获所有可能的异常是个坏主意
为什么C#编译器不能告诉这个函数总是返回或抛出
编译器不会试图模拟程序的工作方式来查看可以执行哪些分支。它只是查看所有可能的分支。在您的情况下,如果出于某种原因,remaingtrys>=0
计算为false,那么它将从方法末尾脱落,而不返回布尔值或抛出值
您可以通过删除for
循环中的复选框来修复它:
public bool DoWorkWithRetry()
{
for (int remainingTries = Constants.MaxRetries;; remainingTries--)
{
// etc...
}
}
那张支票没有任何用处
您还可以重写方法以完全避免问题:
for (int remainingTries = Constants.MaxRetries; remainingTries >= 0; remainingTries--)
{
try
{
return DoWork();
}
catch (Exception ex)
{
// fall through to retry
}
}
throw new WorkException(
String.Format("Failed after {0} retries.", Constants.MaxRetries),
ex);
也请不要抓住和吞下所有的例外。捕获您知道的特定异常。捕获所有可能的异常是一个坏主意。它必须非常聪明,才能知道for循环中的内容是否会被执行。为了让它知道,它必须测试For循环是否实际被执行,因为MaxRitries>=0
它必须非常聪明,无法知道For循环中的内容是否被执行过。为了让它知道,它必须测试For循环是否实际得到执行,因为MaxRitries>=0
编译器只是遵循语言规范
该语言不尝试执行“如果你从一个整数开始,然后反复减去一,你总会在某个点上碰到零”的分析。这甚至假设常量.MaxRetries
是编译时常量
基本上,语言规范具有可访问性规则,如果其中任何一项为真,则可访问for
语句的端点(C#4规范第8.8.3节):
for
语句包含一个可访问的break
语句,该语句退出for
语句
for
语句是可访问的,并且存在for条件,并且没有常量值true
后一点是这里的情况,因此可以到达for
语句的末尾。不允许访问非void方法的结尾,因此会出现错误。(C规范第8.1节)
另一种方法是让语言变得越来越复杂。我完全同意不进行编译。编译器只是遵循语言规范
该语言不尝试执行“如果你从一个整数开始,然后反复减去一,你总会在某个点上碰到零”的分析。这甚至假设常量.MaxRetries
是编译时常量
基本上,语言规范具有可访问性规则,如果其中任何一项为真,则可访问for
语句的端点(C#4规范第8.8.3节):
for
语句包含一个可访问的break
语句,该语句退出for
语句