A Less Ugly Switch Statement For C#
I know switch statements are considered “evil” because they are very procedural code, they violate the Open-Closed Principle, etc etc. But every now and then I don’t see a need to do anything more than a switch statement because the complexity of the scenario does not need anything more, and the code’s maintainability is not going to be so adversely affected by it.
I had such a case today, when examining the “Status” value – an enum – that is found on the data structure returned by a web service call. Here’s the original code:
1: switch (newContainer.Status)
2: {
3: case ScannedAssetState.ConfirmAssetRemove:
4: {
5: ConfirmAssetRemove(newContainer.TagInfo, assetTag);
6: break;
7: }
8: case ScannedAssetState.Error:
9: {
10: View.ShowError(newContainer.Errors.FirstOrDefault());
11: break;
12: }
13: case ScannedAssetState.Success:
14: {
15: RestartWithNewContainer(newContainer.TagInfo);
16: break;
17: }
18: default:
19: {
20: Init(newContainer.TagInfo);
21: break;
22: }
23: }
</div> </div>
Though this code isn’t horrible, I do tend to hate the excessive syntax of switch statements. So… I wrote a simple fluent API to condense this code. Here’s the end result:
1: Switch.On(newContainer.Status)
2: .Case(ScannedAssetState.ConfirmAssetRemove, () => ConfirmAssetRemove(newContainer.TagInfo, assetTag))
3: .Case(ScannedAssetState.Error, () => View.ShowError(newContainer.Errors.FirstOrDefault()))
4: .Case(ScannedAssetState.Success, () => RestartWithNewContainer(newContainer.TagInfo))
5: .Default(() => Init(newContainer.TagInfo));
</div> </div>
And here’s the simple way I implemented it:
1: public static class Switch
2: {
3: public static Switch<T> On<T>(T value)
4: {
5: return new Switch<T>(value);
6: }
7: }
8:
9: public class Switch<T>
10: {
11: private bool hasBeenHandled;
12: private readonly T value;
13:
14: public Switch(T value)
15: {
16: this.value = value;
17: }
18:
19: public Switch<T> Case(T comparisonValue, Action action)
20: {
21: if (AreEqual(value, comparisonValue))
22: {
23: hasBeenHandled = true;
24: action();
25: }
26: return this;
27: }
28:
29: public void Default(Action action)
30: {
31: if (!hasBeenHandled)
32: action();
33: }
34:
35: private bool AreEqual(T actualValue, T comparisonValue)
36: {
37: return Equals(actualValue, comparisonValue);
38: }
39: }
</div> </div>
I’m sure the AreEqual method could use some work to make it more robust, but it satisfied my current need just fine.
Of course, this code is nothing ground-breaking and I’m sure plenty of people will tell me how much worse it is than the original, and how I should have / could have avoided a switch statement in the first place… Meh… It was a fun little exercise. We’ll see how long it actually lives in my code base.