处理枚举时,切换语句没有默认值

Mar*_*ark 35 .net c# enums switch-statement

自从我开始使用.NET以来,这一直是我的一个宠儿,但我很好奇,以防我错过了什么.我的代码片段无法编译(请原谅示例的强制性质),因为(根据编译器)缺少return语句:

public enum Decision { Yes, No}

    public class Test
    {
        public string GetDecision(Decision decision)
        {
            switch (decision)
            {
                case Decision.Yes:
                    return "Yes, that's my decision";
                case Decision.No:
                    return "No, that's my decision";

            }
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在我知道我可以简单地放置一个默认语句来摆脱编译器警告,但在我看来,不仅是冗余代码,它的危险代码.如果枚举在另一个文件中并且另一个开发人员出现并将Maybe添加到我的枚举中,它将由我的默认子句处理,该子句对Maybe s 一无所知,并且我们很可能会引入逻辑错误.

然而,如果编译器允许我使用上面的代码,那么它可以识别我们有问题,因为我的case语句将不再覆盖枚举中的所有值.当然听起来对我来说更安全.

这对我来说根本就是错误的,我想知道它是否只是我缺少的东西,还是我们在switch语句中使用枚举时必须非常小心?

编辑: 我知道我可以在默认情况下引发异常或在交换机外添加一个返回,但这仍然是根本不能解决编译错误,这不应该是错误.

关于enum真的只是一个int,这是.NET肮脏的小秘密之一,真的非常令人尴尬.让我声明一个有限数量的可能性的枚举,并给我一个汇编:

Decision fred = (Decision)123;
Run Code Online (Sandbox Code Playgroud)

然后如果有人尝试这样的事情,则抛出异常:

int foo = 123;
Decision fred = (Decision)foo;
Run Code Online (Sandbox Code Playgroud)

编辑2:

有些人对enum在不同的程序集中会发生什么以及如何导致问题发表评论.我的观点是,这是我认为应该发生的行为.如果我更改方法签名,这将导致问题,我的前提是更改枚举应该是相同的.我的印象是很多人都不认为我理解.NET中的枚举.我只是认为这种行为是错误的,我希望有人可能知道一些非常模糊的功能会改变我对.NET枚举的看法.

Eri*_*ert 37

哎呀,这种情况远比处理枚举更糟糕.我们甚至不为布尔做这个!

public class Test {        
  public string GetDecision(bool decision) {
    switch (decision) {
       case true: return "Yes, that's my decision";                
       case false: return "No, that's my decision"; 
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

产生相同的错误.

即使你解决了枚举能够承担任何价值的所有问题,你仍然会遇到这个问题.语言的流分析规则根本不认为没有默认值的开关是所有可能代码路径的"穷举",即使你和我知道它们也是如此.

我非常想解决这个问题,但坦率地说,我们有很多优先事项而不是解决这个愚蠢的小问题,所以我们从未接触过它.

  • 是的.事实上,枚举只不过是花哨的内容,而且枚举可以从版本变为版本,这使得它们使用起来很危险.那是不幸的; 下次你从头开始设计一个类型系统,你就会知道不要重复这个错误. (9认同)
  • 感谢Eric能够通过我的ramblings了解问题的核心.但是,你不是看到在枚举的情况下实际上可能导致问题,通过强制一个冗余的默认情况,我变成一个危险的. (4认同)

Tho*_*que 17

这是因为值decision实际上可能是不属于枚举的值,例如:

string s = GetDecision((Decision)42);
Run Code Online (Sandbox Code Playgroud)

编译器或CLR不会阻止这种事情.该值也可以是枚举值的组合:

string s = GetDecision(Decision.Yes | Decision.No);
Run Code Online (Sandbox Code Playgroud)

(即使枚举没有Flags属性)

因此,您应始终default在切换中放置一个案例,因为您无法明确检查所有可能的值


Bry*_*tts 15

在default子句中抛出异常:

default:
    throw new ArgumentOutOfRangeException("decision");
Run Code Online (Sandbox Code Playgroud)

这可确保涵盖所有可能的路径,同时避免因添加新值而导致的逻辑错误.


Dim*_*kis 7

public enum Decision { Yes, No}

public class Test
{
    public string GetDecision(Decision decision)
    {
        switch (decision)
        {
            case Decision.Yes:
                return "Yes, that's my decision";
            case Decision.No:
                return "No, that's my decision";
            default: throw new Exception(); // raise exception here.

        }
    }
}
Run Code Online (Sandbox Code Playgroud)