我有以下普查员:
enum Foo { Bar, Baz };
在以下代码中,编译器将中止错误:
use of unassigned local variable 'str'
代码:
string str;
Foo foo = Foo.Bar;
switch (foo)
{
case Foo.Bar: str = "a"; break;
case Foo.Baz: str = "b"; break;
}
str.ToLower();
switch
涵盖了枚举器的所有可能值。但编译器仍然认为str
可能未被分配。这是为什么?当然我可以在那里放一个default
的情况,但这是错误的,因为错误不会在编译时被捕获。例如,如果稍后修改了Foo
枚举并添加了新值,那么然后就可以获得编译器错误。如果我使用default
大小写,则重新编译时不会捕获错误。
我认为没有办法让编译器接受switch
没有default
案例而如果稍后会延长Foo
则会引发错误?
答案 0 :(得分:2)
我想没有办法让编译器接受没有默认情况的开关,如果稍后扩展Foo会引发错误?
这是对的。简而言之,编译器执行此操作的原因是,通过对foo
进行类型转换,可以为enum Foo
分配一个不是有效int
值的值,可以绕过switch
的所有情况。
我在这种情况下使用的解决方案是添加一个断言:
switch (foo)
{
case Foo.Bar: str = "a"; break;
case Foo.Baz: str = "b"; break;
default: Debug.Assert(false, "An enum value is not covered by switch: "+foo);
}
答案 1 :(得分:1)
枚举是静态类型和类型检查。但是检查不会延伸以确保枚举值仅假定定义的值。实际上,对于Flags
枚举,变量通常不会假定任何单个定义的值。
就像那样:
Foo f = (Foo)1234; //valid
这就是为什么switch
可以在运行时选择default
案例而str
最终可能会在未初始化状态下使用。
某些语言的构造比.NET枚举更强大,例如Haskell和F#。
答案 2 :(得分:1)
枚举本质上是一个int,可以为它分配任何int值。这通常不会发生,但这就是为什么你需要处理默认情况或只是声明字符串的默认值(如null)
答案 3 :(得分:1)
当然我可以在那里放一个默认案例,但这是错误的
根据良好做法。您的枚举仍然可以包含其他数值,因为C#中的枚举只是基础数字表示上方的编译时间层 - 请考虑const
字段。 Foo f = (Foo)int.MaxValue;
仍然会编译并运行,但现在你没有切换案例。
根据您的界面,您可以将默认情况设置为异常,使用null定义str
或使用空字符串。
答案 4 :(得分:0)
最好的办法是在第一行用空字符串初始化str。编译器不能(或不会)尝试深入分析开关逻辑。