The opinions expressed herein are my own personal opinions. They are not necessarily fact or sactioned by any other person or organization. If you disagree that's your right. It's also my right to not care.
© Copyright 2010, Chris Tacke
When we use a language, often we tend to overlook some of the more obvious constructs or be frustrated by what we think should work. For example, assume we have this simple problem - our function receives a value and based on that value we run through a switch, but we have code that will be run for multiple cases. Explaining what I mean in words is tough - so let's look at what I'm trying to say in code. Assume we have these enums:
[Flags]enum Foo{ NoFoo = 0, FooA = 1, FooB = 2, FooC = 4}enum Bar{ A, B, C}
We want a function that will take in a Bar, and based on that create a Foo. If Bar is A, the the resulting Foo is a combination of FooA, FooB and FooC. If Bar is B, then it's a combination of FooB and FooC. If Bar is C, then the result is just FooC. In C, we'd just do this:
Foo FooBar(Bar bar){ Foo foo = Foo.NoFoo; switch (bar) { case Bar.A: foo |= Foo.FooA; case Bar.B: foo |= Foo.FooB; case Bar.C: foo |= Foo.FooC; break; } return foo;}
Letting each case fall into the next intentionally. Yes it's a contrived example, but you get the idea. There are cases when we need to do processing like this (like a project I'm doing right now).
Well C# doesn't like this type of construct - I'm not certain why it's illegal (other than missing breaks are common bugs) - but the compiler will say 'Error: Control cannot fall through from one case label ('case 0:') to another'. So you might code a 'fix' like this:
Foo FooBar(Bar bar){ Foo foo = Foo.NoFoo; switch (bar) { case Bar.A: foo |= Foo.FooA; break; case Bar.B: foo |= Foo.FooA; foo |= Foo.FooB; break; case Bar.C: foo |= Foo.FooA; foo |= Foo.FooB; foo |= Foo.FooC; break; } return foo;}
Not too bad, but if you have to do more processing than a single line it gets ugly and maintainability goes downhill fast.
The thing to keep in mind in C# is that those case statements are actually labels, so you can use them as such, meaning they are valid goto targets, so this code is perfectly valid:
Foo FooBar3(Bar bar){ Foo foo = Foo.NoFoo; switch (bar) { case Bar.A: foo |= Foo.FooA; goto case Bar.B; case Bar.B: foo |= Foo.FooB; goto case Bar.C; case Bar.C: foo |= Foo.FooC; break; } return foo;}
Remember Me