15

Why do I get a "not all code paths return a value", for VeryBoolToBool() in the following code?

public enum VeryBool { VeryTrue, VeryFalse };
public bool VeryBoolToBool(VeryBool veryBool)
{
    switch(veryBool)
    {
        case VeryBool.VeryTrue:
            return true;

        case VeryBool.VeryFalse:
            return false;

        // Un-commenting the unreachable(?) default clause will solve this
        // default:
        //    throw new HowTheHellDidIGetHereException();
    }
}

Can't the compiler see there are no other options for VeryBool?

bavaza
  • 9,473
  • 10
  • 59
  • 95

1 Answers1

17

Can't the compiler see there are no other options for VeryBool?

Nope, because there are. For example, I could call:

VeryBoolToBool((VeryBool) 5);

Enums in C# are not limited sets of values. They're effectively named numbers, with additional compile-time type safety in that there aren't implicit conversions between enums or between enums and numbers. (There are explicit conversions though.) The explicit conversions do not ensure that the value in question is one with a name, however.

Beyond that, switch in C# never checks whether all possible values of the type are explicitly listed. The end of a switch statement is always deemed "reachable" unless there's a default case (and all cases terminate). More precisely, from the end of section 8.7.2 of the C# 5 specification:

The end point of a switch statement is reachable if at least one of the following is true:

  • The switch statement contains a reachable break statement that exits the switch statement.
  • The switch statement is reachable, the switch expression is a non-constant value, and no default label is present.
  • The switch statement is reachable, the switch expression is a constant value that doesn’t match any case label, and no default label is present.
Jon Skeet
  • 1,335,956
  • 823
  • 8,931
  • 9,049
  • Hmm. I was wondering if this choice was aimed to ease the implementation of enums in .Net, or is there some benefit in doing stuff like Marc's `VeryBool val = (VeryBool)42;`? – bavaza Dec 24 '13 at 11:10
  • 4
    @bavaza: There are times when it's useful for enums to behave like this - but plenty of others where it's not. I wish there were a "strict enum" type in .NET, but for the moment we need to live with what we've got :( – Jon Skeet Dec 24 '13 at 11:12
  • 1
    The most common case where you would want this behavior is when your `bool` is being used as a bit field (for flags). If you used code [like this](http://stackoverflow.com/a/8462/18192), you could then use `MyEnum foo = MyEnum.First | MyEnum.Second`. – Brian Dec 24 '13 at 14:32