5

I was wondering if it was possible to conditionally break out of a case in a switch statement in C#. Take the following example.

MediaStream photoMediaStream = null;
switch (photoSize)
{
    case PhotoSize.Normal:
        if (imageWidth >= NormalWidth && imageWidth % NormalWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = NormalWidth});
            break;
        }
    case PhotoSize.Small:
        if (imageWidth >= SmallWidth && imageWidth % SmallWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = SmallWidth});
            break;
        }
    case PhotoSize.Thumb:
        if (imageWidth >= ThumbWidth && imageWidth % ThumbWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = ThumbWidth});
            break;
        }
}

Basically, if the conditional is true I want to do something and then break out of the switch statement, but if not I just want to fall through to the next case.

Kyle
  • 4,261
  • 11
  • 46
  • 85
  • Did you try it? What were the results? – Ayush Mar 14 '12 at 15:18
  • If `photoSize == PhotoSize.Normal` and the `if` fails surely none of the other cases would be valid anyway? – Barry Kaye Mar 14 '12 at 15:20
  • Yeah, sorry. I got compiler errors for each case statement saying "Control cannot fall through from one case label to another" – Kyle Mar 14 '12 at 15:21
  • 1
    do you only have 3 cases? if so, wouldn't it be acceptable to just do if...else if...else if? don't think it'd be that huge of a performance hit. – esvendsen Mar 14 '12 at 15:21
  • @BarryKaye Not quite. NormalWidth > SmallWidth > ThumbWidth so if case 0 is invalid theoretically case 1 or 2 could be. – Kyle Mar 14 '12 at 15:22

8 Answers8

10

Since you can't implicitly fall through to the next case, you must do it explicitly, using the goto statement. This is one of the rare cases where the use of this statement is acceptable...

MediaStream photoMediaStream = null;
switch (photoSize)
{
    case PhotoSize.Normal:
        if (imageWidth >= NormalWidth && imageWidth % NormalWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = NormalWidth});
            break;
        }
        goto case PhotoSize.Small;
    case PhotoSize.Small:
        if (imageWidth >= SmallWidth && imageWidth % SmallWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = SmallWidth});
            break;
        }
        goto case PhotoSize.Thumb;
    case PhotoSize.Thumb:
        if (imageWidth >= ThumbWidth && imageWidth % ThumbWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = ThumbWidth});
            break;
        }
}

Anyway, it would probably be better to refactor it using if statements:

MediaStream GetPhotoMediaStream(PhotoSize photoSize, /* whatever parameters you need... */)
{
    if (photoSize == PhotoSize.Normal)
    {
        if (imageWidth >= NormalWidth && imageWidth % NormalWidth == 0)
        {
            return photoMedia.GetStream(new MediaOptions {Width = NormalWidth});
        }
        photoSize = PhotoSize.Small;
    }
    if (photoSize == PhotoSize.Small)
    {
        if (imageWidth >= SmallWidth && imageWidth % SmallWidth == 0)
        {
            return photoMedia.GetStream(new MediaOptions {Width = SmallWidth});
        }
        photoSize = PhotoSize.Thumb;
    }
    if (photoSize == PhotoSize.Thumb)
    {
        if (imageWidth >= ThumbWidth && imageWidth % ThumbWidth == 0)
        {
            return photoMedia.GetStream(new MediaOptions {Width = ThumbWidth});
        }
    }
    return null;
}
Thomas Levesque
  • 286,951
  • 70
  • 623
  • 758
  • Use of `if` or `if/else` is much cleaner then constrain my self to use a `swithch/case` in a way that I have no other way then use `goto` – Tigran Mar 14 '12 at 15:30
  • 1
    Thanks, I must admit I get a bit excited about a justified use for goto. Can't wait to put this in my code. – Kyle Mar 14 '12 at 15:33
2

No, C# doesn't allow fallthrough in switches, except if there is no code between the cases. See point 8.7.2 of the C# specification:

If the end point of the statement list of a switch section is reachable, a compile-time error occurs.

Ral Zarek
  • 1,058
  • 4
  • 18
  • 25
  • C# doesn't allow **implicit** fallthrough, but you can do it explicitly using `goto` (yeah, I know, goto is evil)... – Thomas Levesque Mar 14 '12 at 15:34
  • Thanks. I think this is where I was getting confused because I had used switch statements in the past where I was falling through with no code between the cases. – Kyle Mar 14 '12 at 15:35
  • @Thomas Levesque: Now that you mention it, I read about `goto case` somewhere, but forgot about it since then because I never needed it. – Ral Zarek Mar 14 '12 at 17:25
2

You can go to an other case with goto case.

switch (photoSize)
{
    case PhotoSize.Normal:
        if (imageWidth >= NormalWidth && imageWidth % NormalWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = NormalWidth});
            break;
        }
        goto case PhotoSize.Small;
    case PhotoSize.Small:
        if (imageWidth >= SmallWidth && imageWidth % SmallWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = SmallWidth});
            break;
        }
        goto case PhotoSize.Thumb;
    case PhotoSize.Thumb:
        if (imageWidth >= ThumbWidth && imageWidth % ThumbWidth == 0)
        {
            photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = ThumbWidth});
            break;
        }
        break;
    }
raznagul
  • 355
  • 2
  • 19
1

C# doesn't support falling through case labels when any code is in between (see Switch statement fallthrough in C#? ).
Thus, you surely can conditionally break - however, you will have to break at the end of each block, too, anyway ;-)

Just use some ifs instead.

Community
  • 1
  • 1
Matthias
  • 12,053
  • 4
  • 49
  • 91
1

No, it's not possible 'cause if the if condition isn't satisfied the program should flow from one case to the next one (and this isn't permitted in C#).

From MSDN:

Execution of the statement list in the selected section begins with the first statement and proceeds through the statement list, typically until a jump statement is reached, such as a break, goto case, return, or throw. At that point, control is transferred outside the switch statement or to another case label.

Unlike C++, C# does not allow execution to continue from one switch section to the next.

Adriano Repetti
  • 65,416
  • 20
  • 137
  • 208
0

Put the "break" outside of If condition..

MediaStream photoMediaStream = null;
switch (photoSize)
{
   case PhotoSize.Normal:
    if (imageWidth >= NormalWidth && imageWidth % NormalWidth == 0)
    {
        photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = NormalWidth});

    }
 break;
 case PhotoSize.Small:
    if (imageWidth >= SmallWidth && imageWidth % SmallWidth == 0)
    {
        photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = SmallWidth});

    }
break;
case PhotoSize.Thumb:
    if (imageWidth >= ThumbWidth && imageWidth % ThumbWidth == 0)
    {
        photoMediaStream = photoMedia.GetStream(new MediaOptions {Width = ThumbWidth});

    }
break;
 }
Raj De Inno
  • 1,092
  • 2
  • 14
  • 33
0

Well, if you need conditionise a execution of your code in the function, do not use switch/case, but if statements chain. In the moment you want to "break" an execution flow, use return.

Tigran
  • 61,654
  • 8
  • 86
  • 123
0

As others have mentioned, C# doesn't permit fall-through. It does permit stacking of cases, but that isn't going to help you. You could, however, achieve that using goto statements outside the if condition to explicitly transfer control to another (or in your case, the next) case.

Before someone says 'OMG!! eww...goto!', I must add that there are few cases that warrant the use of gotos. This seems to be one of them. As long as not misused, there's nothing inherently wrong with gotos.

Ayush
  • 41,754
  • 51
  • 164
  • 239