无法访问的代码,但是有异常可以访问

时间:2019-03-12 08:17:19

标签: c# exception unreachable-code

此代码是从ODBC连接的数据库读取和写入的应用程序的一部分。它在数据库中创建一条记录,然后检查是否已成功创建记录,然后返回true

我对控制流程的理解如下:

command.ExecuteNonQuery()被记录为在“方法调用对该对象的当前状态无效”时抛出Invalid​Operation​Exception。因此,如果发生这种情况,将try块的执行停止,将执行finally块,然后在底部执行return false;

但是,我的IDE声称return false;是无法访问的代码。而且似乎是事实,我可以删除它,并且可以毫无抱怨地进行编译。但是,对我来说,似乎抛出上述异常的代码路径没有返回值。

private static bool createRecord(String table,
                                 IDictionary<String,String> data,
                                 System.Data.IDbConnection conn,
                                 OdbcTransaction trans) {

    [... some other code ...]

    int returnValue = 0;
    try {
        command.CommandText = sb.ToString();
        returnValue = command.ExecuteNonQuery();

        return returnValue == 1;
    } finally {
        command.Dispose();
    }

    return false;
}

我在这里理解的错误是什么?

7 个答案:

答案 0 :(得分:146)

Compiler Warning (level 2) CS0162

  

检测到无法访问的代码

     

编译器检测到永远不会执行的代码。

这只是说,编译器通过 Static Analysis 足够了解,无法达到它,并从已编译的IL中完全忽略了它(因此,您的警告)

注意 :您可以通过尝试使用调试器踩到“无法访问的代码”或使用IL来向自己证明这一事实资源管理器

finally可能会在 Exception 上运行,(尽管除此之外)它并不会改变事实(在这种情况下)仍然是 Uncaught Exception < / em>。因此,最后一个return永远不会受到打击。

  • 如果您希望代码继续到最后一个return,则唯一的选择是 Catch Exception ;

    < / li>
  • 如果不这样做,请将其保留原样,然后删除return

示例

try 
{
    command.CommandText = sb.ToString();
    returnValue = command.ExecuteNonQuery();

    return returnValue == 1;
}
catch(<some exception>)
{
   // do something
}
finally 
{
    command.Dispose();
}

return false;

引用文档

try-finally (C# Reference)

  

通过使用finally块,您可以清理所有   分配在try块中,即使出现异常也可以运行代码   发生在try块中。通常,finally块的语句   当控件离开try语句时运行。可以转移控制权   因正常执行,执行中断而发生   继续,转到或返回语句,或传播异常   在try语句之外。

     

在已处理的异常内,可以保证关联的finally块   要运行。 但是,如果未处理异常,则执行   finally块取决于异常展开操作的方式   触发。反过来,这取决于计算机的设置方式。

     

通常,当未处理的异常终止应用程序时,无论是   不是finally块运行并不重要。 但是,如果您有   在即使在这种情况下也必须运行的finally块中的语句,   一种解决方案是在try-finally语句中添加一个catch块。   或者,您可以捕获可能会在   在调用堆栈上方的try-finally语句的try块。那   是,您可以在调用该方法的方法中捕获异常   包含try-finally语句或在调用方法中   该方法,或调用堆栈中的任何方法。如果是   未捕获,是否执行finally块取决于是否   操作系统选择触发异常展开操作。

最后

使用支持IDisposable接口(旨在释放非托管资源)的任何内容时,可以将其包装在using语句中。编译器将生成try {} finally {}并在对象上内部调用Dispose()

答案 1 :(得分:86)

  

将执行finally块,然后执行return false;在底部。

错了。 finally不会吞下该异常。它很荣幸,并且异常将被正常抛出。它将仅在代码块结束之前(无论是否有异常)在代码的最后执行代码。

如果您希望吞下该异常,则应使用其中没有catch的{​​{1}}块。

答案 2 :(得分:27)

警告是因为您没有使用catch并且您的方法基本上是这样写的:

bool SomeMethod()
{
    return true;
    return false; // CS0162 Unreachable code detected
}

由于仅使用finally进行处置,因此首选的解决方案是利用using模式:

using(var command = new WhateverCommand())
{
     ...
}

这足以确保将调用Dispose。保证可以在成功执行代码块之后或在调用堆栈中某些catch down 之前(之前的父调用已关闭,对吗?)被调用。

如果不是要处理的话,那么

try { ...; return true; } // only one return
finally { ... }

就足够了,因为您将不需要,只需在方法末尾返回false(不需要该行)。您的方法是命令执行的返回结果(truefalse),或者将引发异常否则


还考虑通过包装预期的异常来抛出自己的异常(签出InvalidOperationException constructor):

try { ... }
catch(SomeExpectedException e)
{
    throw new SomeBetterExceptionWithExplanaition("...", e);
}

通常用于对调用者说一些比嵌套调用异常所讲的更有意义(有用)的东西。


大多数时候,您实际上并不关心未处理的异常。有时,即使未处理异常,也需要确保调用finally。在这种情况下,您只需自己抓住并重新抛出(请参阅this answer):

try { ... }
catch { ...; throw; } // re-throw
finally { ... }

答案 3 :(得分:8)

您没有catch块,因此仍会引发异常,从而阻止了返回。

  

将执行finally块,然后执行return false;在底部。

这是错误的,因为将执行finally块,然后会有未捕获的异常。

finally块用于清除,它们不捕获异常。在返回之前抛出异常,因此,永远不会到达返回,因为在之前抛出了异常。

您的IDE是正确的,它将永远不会到达,因为将引发异常。只有catch个块才能捕获异常。

the documentation中读取,

  

通常,当未处理的异常结束应用程序时,是否运行finally块并不重要。但是,如果在即使在那种情况下都必须运行的finally块中有语句,则一种解决方案是在try-finally语句中添加catch块。或者,您可以捕获可能在调用堆栈上方的try-finally语句的try块中引发的异常。也就是说,您可以在调用包含try-finally语句的方法的方法中,在调用该方法的方法中或在调用堆栈中的任何方法中捕获异常。 如果未捕获到异常,则finally块的执行取决于操作系统是否选择触发异常展开操作

这清楚地表明,finally并非旨在捕获异常,并且如果在catch语句之前有空的finally语句,那您将是正确的。

答案 4 :(得分:7)

引发异常时,堆栈将展开(执行将移出函数)而不返回值,并且函数上方堆栈帧中的任何catch块将捕获异常。

因此,<Label Content="{Binding Source=HelloWorld, Converter={StaticResource ResourceConverter}, ConverterCulture=en-US}" /> 将永远不会执行。

尝试手动引发异常以了解控制流:

return false

答案 5 :(得分:4)

最后一条语句return false无法访问,因为try块缺少处理异常的catch部分,因此在finally块之后重新抛出了异常,并且执行从不到达最后一条语句。

答案 6 :(得分:2)

您的代码中有两个返回路径,由于第二个路径,第二个路径不可访问。 tryreturn returnValue == 1;中的最后一条语句提供了正常的返回值,因此您永远无法在方法块末尾到达return false;

FWIW,与finally块相关的执行顺序是:将首先对在try块中提供返回值的表达式进行求值,然后将执行finally块,然后将计算出的表达式值设为返回(在try块内)。

关于异常的流程...如果没有catch,则finally将在异常发生之前执行,然后将异常从方法中抛出。没有“返回”路径。