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)
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 2:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 3:</span> <span style="color: #0000ff">case</span> ScannedAssetState.ConfirmAssetRemove:</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 4:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 5:</span> ConfirmAssetRemove(newContainer.TagInfo, assetTag);</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 6:</span> <span style="color: #0000ff">break</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 7:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 8:</span> <span style="color: #0000ff">case</span> ScannedAssetState.Error:</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 9:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 10:</span> View.ShowError(newContainer.Errors.FirstOrDefault());</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 11:</span> <span style="color: #0000ff">break</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 12:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 13:</span> <span style="color: #0000ff">case</span> ScannedAssetState.Success:</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 14:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 15:</span> RestartWithNewContainer(newContainer.TagInfo);</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 16:</span> <span style="color: #0000ff">break</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 17:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 18:</span> <span style="color: #0000ff">default</span>:</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 19:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 20:</span> Init(newContainer.TagInfo);</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 21:</span> <span style="color: #0000ff">break</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 22:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 23:</span> }</pre>
<p>
<!--CRLF--></div> </div>
<p>
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:
</p>
<div>
<div>
<pre><span style="color: #606060"> 1:</span> Switch.On(newContainer.Status)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 2:</span> .Case(ScannedAssetState.ConfirmAssetRemove, () => ConfirmAssetRemove(newContainer.TagInfo, assetTag))</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 3:</span> .Case(ScannedAssetState.Error, () => View.ShowError(newContainer.Errors.FirstOrDefault()))</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 4:</span> .Case(ScannedAssetState.Success, () => RestartWithNewContainer(newContainer.TagInfo))</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 5:</span> .Default(() => Init(newContainer.TagInfo));</pre>
<p>
<!--CRLF--></div> </div>
<p>
And here’s the simple way I implemented it:
</p>
<div>
<div>
<pre><span style="color: #606060"> 1:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> <span style="color: #0000ff">class</span> Switch</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 2:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 3:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">static</span> Switch<T> On<T>(T <span style="color: #0000ff">value</span>)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 4:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 5:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">new</span> Switch<T>(<span style="color: #0000ff">value</span>);</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 6:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 7:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 8:</span>  </pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 9:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">class</span> Switch<T></pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 10:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 11:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">bool</span> hasBeenHandled;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 12:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">readonly</span> T <span style="color: #0000ff">value</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 13:</span>  </pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 14:</span> <span style="color: #0000ff">public</span> Switch(T <span style="color: #0000ff">value</span>)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 15:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 16:</span> <span style="color: #0000ff">this</span>.<span style="color: #0000ff">value</span> = <span style="color: #0000ff">value</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 17:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 18:</span>  </pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 19:</span> <span style="color: #0000ff">public</span> Switch<T> Case(T comparisonValue, Action action)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 20:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 21:</span> <span style="color: #0000ff">if</span> (AreEqual(<span style="color: #0000ff">value</span>, comparisonValue))</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 22:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 23:</span> hasBeenHandled = <span style="color: #0000ff">true</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 24:</span> action();</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 25:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 26:</span> <span style="color: #0000ff">return</span> <span style="color: #0000ff">this</span>;</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 27:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 28:</span>  </pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 29:</span> <span style="color: #0000ff">public</span> <span style="color: #0000ff">void</span> Default(Action action)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 30:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 31:</span> <span style="color: #0000ff">if</span> (!hasBeenHandled)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 32:</span> action();</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 33:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 34:</span>  </pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 35:</span> <span style="color: #0000ff">private</span> <span style="color: #0000ff">bool</span> AreEqual(T actualValue, T comparisonValue)</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 36:</span> {</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 37:</span> <span style="color: #0000ff">return</span> Equals(actualValue, comparisonValue);</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 38:</span> }</pre>
<p>
<!--CRLF-->
</p>
<pre><span style="color: #606060"> 39:</span> }</pre>
<p>
<!--CRLF--></div> </div>
<p>
I’m sure the AreEqual method could use some work to make it more robust, but it satisfied my current need just fine.
</p>
<p>
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.
</p>
