【问题标题】:Switch + Enum = Not all code paths return a valueSwitch + Enum = 并非所有代码路径都返回值
【发布时间】:2010-09-02 08:14:33
【问题描述】:

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

    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 不可能具有任何其他价值,是吗?编译器不应该足够聪明来解决这个问题吗?

【问题讨论】:

    标签: c#


    【解决方案1】:

    不,您可以使用任何转换为​​Tileint 值。试试这个:

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

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

    我会建议一个默认情况下抛出ArgumentException(或者可能是ArgumentOutOfRangeException)。

    【讨论】:

    • 由于该方法是私有的,因此调用者应该只传递好的东西(因为调用者的作者是 ,而不是你的用户)我建议使用 Debug .Fail("Bad caller! No biscuit!") 等默认情况下。
    • @Eric: 可能...除此之外,您仍然需要返回某些内容或抛出异常以及以满足可达性要求。就我个人而言,我从来都不是Debug.* 的粉丝——我倾向于在发布模式下看到与调试模式相同的异常,但这可能只是我自己。
    【解决方案2】:

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

    在这两种情况下,您都会收到相同的“非 void 方法中的可到达端点”错误。

    这只是 C# 规范的“可达性检查”部分的疏忽。如果 switch 语句没有默认节句点,我们将其定义为可到达的端点。对于彻底消耗其输入的每一个可能值的开关,没有特殊的规定。这是语言设计者遗漏的一个极端情况,而且它从来没有得到足够高的优先级来修复它。

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

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

    【讨论】:

    • 该死的,我现在想给你两张支票。哈哈。。说的很对。我认为这是真正的原因!
    【解决方案3】:

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

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

    【讨论】:

    • "...如果您的 t 值与任何 switch case 都不匹配..." - 这正是我的问题。 如何它不能匹配任何开关案例?
    • 因为正如 Jon 所说,Enum 实际上只是一个整数的表示。而且由于您可以将整数转换为 Tile 枚举,因此您可以在技术上传递无效参数。
    【解决方案4】:

    添加默认情况:

        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】:
    switch (t)
    {
        case Tile.Empty:
            return ".";
        case Tile.White:
            return "W";
        case Tile.Black:
            return "B";
        default: throw new NotSupportedException();
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-12-17
      • 1970-01-01
      • 1970-01-01
      • 2021-11-08
      • 2013-10-06
      相关资源
      最近更新 更多