Switch + Enum =并非所有代码路径都返回一个值

mpe*_*pen 14 c#

我只是好奇为什么这个代码......

    enum Tile { Empty, White, Black };
    private string TileToString(Tile t)
    {
        switch (t)
        {
            case Tile.Empty:
                return ".";
            case Tile.White:
                return "W";
            case Tile.Black:
                return "B";
        }
    }
Run Code Online (Sandbox Code Playgroud)

抛出那个错误.它不可能t承担任何其他价值,是吗?难道编译器不应该足够聪明地弄明白吗?

Jon*_*eet 31

不,您可以使用int转换为的任何值Tile.试试这个:

Tile t = (Tile) 5;
string s = TileToString(t);
Run Code Online (Sandbox Code Playgroud)

枚举是数字的一组名称,实际上......但是编译器和CLR都没有强制枚举类型的值具有名称.这是一种痛苦,但它存在......

我会建议抛出ArgumentException(或可能ArgumentOutOfRangeException)的默认情况.

  • @Eric:可能......除此之外你还需要返回一些东西或抛出异常*以满足可达性要求.就个人而言,我从来都不喜欢`Debug.*` - 我倾向于在发布模式下看到与调试模式相同的异常,但这可能只是我. (5认同)
  • 由于该方法是私有的,因此调用者应该只传递好东西(因为调用者的作者是*你*,而不是你的用户)我建议一个Debug.Fail("错误调用者!没有饼干!")或者类似于默认情况. (4认同)

Eri*_*ert 23

Jon当然完全正确,枚举可以具有其基础类型的任何值,因此切换不是详尽的,因此存在不返回的代码路径.但是,这不是对问题的完整分析.即使转换是详尽的,你仍然会得到错误.

试试吧:

int M(bool b) 
{
    switch(b)
    {
        case true : return 123;
        case false: return 456;
    } 
}
Run Code Online (Sandbox Code Playgroud)

要么

int M(byte b) 
{
    switch(b)
    {
        case 0: case 1: case 2: ... all of them ... case 255: return 123;
    } 
}
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,您将获得相同的"非void方法中的可到达终点"错误.

这只是C#规范"可达性检查"部分的疏忽.如果switch语句的端点没有默认的section,则将它们的端点定义为可达.对于彻底消耗其输入的每个可能值的开关,没有特别的分配.这是语言设计师错过的一个极端案例,并且从来没有达到过高的优先级来解决它.

有关switch语句分析的其他三个有趣事实,请参阅:

http://ericlippert.com/2009/08/13/four-switch-oddities/