开发者

Switch + Enum = Not all code paths return a value

I'm just curious why this code...

    enum Tile { Empty, White, Black };
    private string TileToString(Tile t)
    {
        switch (t)
        {
            case Tile.Empty:
                return ".";
            case Tile.White:
        开发者_Go百科        return "W";
            case Tile.Black:
                return "B";
        }
    }

Throws that error. It's not possible for t to take on any other value, is it? Shouldn't the compiler be clever enough to figure that out?


No, you can use any int value converted to Tile. Try this:

Tile t = (Tile) 5;
string s = TileToString(t);

An enum is a set of names for numbers, effectively... but neither the compiler nor the CLR enforces that a value of the enum type has a name. It's a pain, but there it is...

I would suggest a default case which threw ArgumentException (or possibly ArgumentOutOfRangeException).


Jon is of course entirely correct that an enum can have any value of its underlying type, and therefore the switch is not exhaustive, and therefore there is a code path that does not return. However, that is not a complete analysis of the issue. Even if it were the case that the switch was exhaustive, you'd still get the error.

Try it:

int M(bool b) 
{
    switch(b)
    {
        case true : return 123;
        case false: return 456;
    } 
}

Or

int M(byte b) 
{
    switch(b)
    {
        case 0: case 1: case 2: ... all of them ... case 255: return 123;
    } 
}

In both these cases you'll get the same "reachable end point in non-void method" error.

This is simply an oversight in the "reachability checking" section of the C# specification. We define the end point of a switch statement as being reachable if it doesn't have a default section, period. There is no special dispensation for switches that exhaustively consume every possible value of their input. It's a corner case that the language designers missed, and it's never been nearly a high enough priority to fix it.

For three other interesting facts about analysis of switch statements, see:

http://ericlippert.com/2009/08/13/four-switch-oddities/


This is because if your value for t does not match any of the switch cases it will fall out of the switch and thus your method will not return a value. You have, however, declared that it will return a string. You need to add a default into the switch, or a return null:

enum Tile { Empty, White, Black };
    private string TileToString(Tile t)
    {
        switch (t)
        {
            case Tile.Empty:
                return ".";
            case Tile.White:
                return "W";
            case Tile.Black:
                return "B";
        }
        return null;
    }


Add the default case:

    enum Tile { Empty, White, Black };
    private string TileToString(Tile t)
    {
        switch (t)
        {
            case Tile.Empty:
                return ".";
            case Tile.White:
                return "W";
            case Tile.Black:
                return "B";
            default:
                return ".";
        }
    }


switch (t)
{
    case Tile.Empty:
        return ".";
    case Tile.White:
        return "W";
    case Tile.Black:
        return "B";
    default: throw new NotSupportedException();
}

As Jon pointed out, the value is integral - an enum can be cast from any integral value. You just need to handle the default.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜