代码之家  ›  专栏  ›  技术社区  ›  mpen

switch+enum=并非所有代码路径都返回值

c#
  •  13
  • mpen  · 技术社区  · 14 年前

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

        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";
            }
        }
    

    抛出那个错误。这是不可能的 t 要承担任何其他价值,是吗?编译器不应该足够聪明来解决这个问题吗?

    5 回复  |  直到 10 年前
        1
  •  30
  •   Jon Skeet    14 年前

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

    Tile t = (Tile) 5;
    string s = TileToString(t);
    

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

    我建议一个默认案例 ArgumentException (或可能) ArgumentOutOfRangeException )

        2
  •  23
  •   Eric Lippert    10 年前

    当然,jon完全正确,一个枚举可以有其基础类型的任何值,因此开关不是完全的,因此有一个不返回的代码路径。 然而 ,这不是对问题的完整分析。 即使在这种情况下,开关是彻底的,你仍然会得到错误。

    试试看:

    int M(bool b) 
    {
        switch(b)
        {
            case true : return 123;
            case false: return 456;
        } 
    }
    

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

    在这两种情况下,您将得到相同的“非空方法中的可到达终点”错误。

    这只是C规范“可到达性检查”部分中的一个监督。我们将switch语句的端点定义为如果没有默认的节、句点,则可以访问。对于完全消耗其输入的每一个可能值的交换机,没有特别的特例。这是语言设计者们忽略的一个小问题,而且它从来都不是解决它的足够高的优先级。

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

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

        3
  •  1
  •   BeRecursive    14 年前

    这是因为如果t的值与任何开关案例都不匹配,它将从开关中掉出来,因此方法不会返回值。但是,您已经声明它将返回一个字符串。您需要在开关中添加一个默认值,或者返回一个空值:

    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";
            }
            return null;
        }
    
        4
  •  1
  •   Jérémie Bertrand Alex Kumbhani    14 年前

    添加默认案例:

        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";
                default:
                    return ".";
            }
        }
    
        5
  •  0
  •   Codesleuth    14 年前
    switch (t)
    {
        case Tile.Empty:
            return ".";
        case Tile.White:
            return "W";
        case Tile.Black:
            return "B";
        default: throw new NotSupportedException();
    }
    

    如jon所指出的,该值是整数-枚举可以从任何整数值强制转换。您只需要处理默认值。