Nikos C.
Nikos C.

Reputation: 51840

Compiler complains about unassigned variable after switch on enum

I have the following enumerator:

enum Foo { Bar, Baz };

In the following code, the compiler aborts with the error:

use of unassigned local variable 'str'

The code:

string str;
Foo foo = Foo.Bar;

switch (foo)
{
    case Foo.Bar: str = "a"; break;
    case Foo.Baz: str = "b"; break;
}

str.ToLower();

The switch covers all the possible values of the enumerator. But the compiler still thinks that str might be unassigned. Why is that? Of course I could put a default case in there, but that would be wrong, since errors are not caught at compile-time. For example, if the Foo enum is modified later on and a new value added, then it would be nice to get a compiler error. If I use a default case, then the error is not caught when recompiling.

I suppose there is no way to get the compiler to accept a switch without a default case and raise an error if Foo is extended later on?

Upvotes: 3

Views: 721

Answers (5)

Honza Brestan
Honza Brestan

Reputation: 10947

Of course I could put a default case in there, but that would be wrong

That would be according to good practices. Your enum can still contain other numeric values, because enums in C# are only compile time layer above the underlying numeric representation - think const fields. Foo f = (Foo)int.MaxValue; will still compile and run, but now you don't have a switch case for it.

Depending on your interface, you may either put a default case with an exception there, define str with null, or an empty string.

Upvotes: 1

Robert Levy
Robert Levy

Reputation: 29073

The enum is essentially an int and any int value could be assigned to it. This usually doesn't happen but is why you need to handle the default case or simply declare the string with a default value (like null)

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726559

I suppose there is no way to get the compiler to accept a switch without a default case and raise an error if Foo is extended later on?

This is correct. Long story short, the reason why the compiler does this is that it is possible to assign foo a value that is not one of a valid enum Foos values by typecasting an int, making it possible to bypass all cases of the switch.

The solution that I use in situations like this is to add an assertion:

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

Upvotes: 3

ths
ths

Reputation: 2942

your best bet is to just initialize str with an empty string in your first line. the compiler can't (or won't) try to analyse the switch logic that deeply.

Upvotes: 0

usr
usr

Reputation: 171178

Enums are statically typed and type checked. But the checking does not extend to ensure that enum values only assume defined values. In fact, for Flags enums variables often do not assume any single defined value.

Like that:

Foo f = (Foo)1234; //valid

And that's why the switch can pick the default case at runtime and str could end up being used in an uninitialized state.

Some languages have stronger constructs than .NET enums such as Haskell and F#.

Upvotes: 1

Related Questions