编译器在打开枚举后抱怨未分配的变量

本文关键字:分配 变量 枚举 编译器 | 更新日期: 2023-09-27 18:20:01

我有以下枚举器:

enum Foo { Bar, Baz };

在以下代码中,编译器中止并返回错误:

使用未分配的局部变量"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的情况,那么在重新编译时不会捕捉到错误。

我想没有办法让编译器在没有default大小写的情况下接受switch,并且如果稍后扩展Foo会引发错误?

编译器在打开枚举后抱怨未分配的变量

我想如果以后扩展Foo,就没有办法让编译器接受没有默认情况的开关并引发错误?

这是正确的。长话短说,编译器这样做的原因是,通过类型转换int,可以为foo分配一个不是有效enum Foo值之一的值,从而可以绕过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);
}

枚举是静态类型化的,并进行类型检查。但检查并没有扩展到确保枚举值只采用已定义的值。事实上,对于Flags,枚举变量通常不采用任何单个定义的值。

比如:

Foo f = (Foo)1234; //valid

这就是为什么switch可以在运行时选择default的情况,而str最终可能在未初始化的状态下使用。

有些语言具有比.NET枚举更强的构造,如Haskell和F#。

枚举本质上是一个int,任何int值都可以分配给它。这通常不会发生,但这就是为什么你需要处理默认情况,或者简单地用默认值(如null)声明字符串

当然,我可以把默认情况放在那里,但这将是错误的

这将符合良好做法。您的枚举仍然可以包含其他数值,因为C#中的枚举只是底层数值表示之上的编译时层——想想const字段。Foo f = (Foo)int.MaxValue;仍将编译和运行,但现在您没有用于它的切换案例

根据您的接口,您可以在其中放置带有异常的默认大小写,也可以用null或空字符串定义str

您的最佳选择是在第一行中使用空字符串初始化str。编译器不能(或不会)尝试对切换逻辑进行深入分析。