并非所有代码路径都返回,但编译器将其视为所有路径都返回

Col*_*ett 4 c# compilation

我想不出一个好的头衔,但我的问题并不像它看起来那么幼稚.

考虑一下:

public static void ExitApp(string message)
{
    // Do stuff
    throw new Exception(...);
}
Run Code Online (Sandbox Code Playgroud)

要么

public static void ExitApp(string message)
{
    // Do stuff
    System.Environment.Exit(-1);
}
Run Code Online (Sandbox Code Playgroud)

这些方法都不会回归.但是当你在别处调用这些方法时:

public int DoStuff()
{
    // Do stuff
    if (foo == 0)
    {
        throw new Exception(...);
    }
    else if (foo == 1)
    {
        // Do other stuff
        return ...;
    }
    else
    {
        ExitApp("Something borked");
    }
}
Run Code Online (Sandbox Code Playgroud)

尝试编译它,你会在DoStuff中得到一个"并非所有代码路径都返回一个值".使用Exception来跟踪对ExitApp的调用似乎很愚蠢,只是为了满足编译器,即使我知道它很好.在ExitApp()中似乎没有任何东西可以表明它永远不会返回.

如何向编译器指示ExitApp永远不会返回,因此,DoStuff的else块也永远不会返回? 这似乎是一个相当简单的错误,它的路径检查无法解释.

即使我只使用第一个ExitApp(抛出异常)并且该方法返回一个int,路径检查器足够聪明,意识到它永远不会返回,所以它不会抱怨int类型.这个编译文件:

public static int ExitApp(string message)
{
    // Do stuff
    throw new Exception(...);
}
Run Code Online (Sandbox Code Playgroud)

但是,鉴于它知道这个ExitApp永远不会返回一个int,它不会将它推断到DoStuff()所以我倾向于认为我的问题没有解决方案.我唯一的选择是在调用ExitApp之后抛出异常.

public int DoStuff()
{
    ...
    else
    {
        ExitApp("Something borked");
        throw new NotImplementedException("Should not reach this");
    }
}
Run Code Online (Sandbox Code Playgroud)

编译器有这种行为的原因吗?

Cra*_*ney 12

我为此目的定义了一个异常:UnreachableException.这看起来似乎是多余的,但这是一种简单的方式来说"嘿,读这个的人,这行不应该被执行!".我通常将它用于某些switch语句的默认情况,但它也适用于此处.

只需在ExitApp行之后抛出一个.

public void int DoStuff()
{
    // Do stuff
    if (foo == 0)
    {
        throw new Exception(...);
    }
    else if (foo == 1)
    {
        // Do other stuff
        return ...;
    }
    else
    {
        ExitApp("Something borked");
        throw new UnreachableException();
    }
}
Run Code Online (Sandbox Code Playgroud)

语言不支持声明一个总是抛出的方法的实际原因只是:它不值得.语言开发人员没有无限的时间来应用我们能想到的每个功能.他们必须优先考虑.

我敢打赌这是你第一次遇到这种情况,看看:明确抛出异常处理问题.他们为什么要费心处理这种罕见的,容易绕过的情况呢?他们可能会花时间实现可选参数,动态或其他一些更有用的东西,并且比能够说函数总是抛出异常更频繁地使用.

这并不是说它永远不会被实施.这种类型的方法信息正是合同在指定时非常好的类型.所以它可能会包含在代码合同中.