<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/" xmlns:copyright="http://blogs.law.harvard.edu/tech/rss" xmlns:image="http://purl.org/rss/1.0/modules/image/">
    <channel>
        <title>Programming</title>
        <link>http://blogs.ipona.com/james/category/72.aspx</link>
        <description>Stuff relating to the techie things I do for a living.</description>
        <language>en-GB</language>
        <copyright>James Hart</copyright>
        <generator>Subtext Version 2.1.0.5</generator>
        <item>
            <title>Dangerous Ideas in C# No. 1: A 'Better' Switch</title>
            <link>http://blogs.ipona.com/james/archive/2008/05/23/Dangerous-Ideas-in-C-No.-1-A-Better-Switch.aspx</link>
            <description>&lt;p&gt;Switch statements are rubbish. Only work on strings and numbers. Require an exact match value.&lt;/p&gt;  &lt;p&gt;Let’s abuse, oh, to pick a C# feature at random, collection initialisers, and use it to make them better!&lt;/p&gt;  &lt;pre class="code"&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;switchValue = &lt;span style="color: #a31515"&gt;"house"&lt;/span&gt;;

&lt;span style="color: blue"&gt;switch &lt;/span&gt;(switchValue)
{
&lt;span style="color: blue"&gt;   case &lt;/span&gt;&lt;span style="color: #a31515"&gt;"hello"&lt;/span&gt;:
      &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Value was hello"&lt;/span&gt;);
      &lt;span style="color: blue"&gt;break&lt;/span&gt;;
   &lt;span style="color: green"&gt;// But how can we handle, say, all other strings that start with h?
   &lt;/span&gt;&lt;span style="color: blue"&gt;default&lt;/span&gt;:
      &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"No match - Fallthrough"&lt;/span&gt;);
      &lt;span style="color: blue"&gt;break&lt;/span&gt;;
}

&lt;span style="color: green"&gt;// here’s one way:
&lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Switch&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(switchValue)
{
  { &lt;span style="color: #a31515"&gt;"hello"&lt;/span&gt;, 
     ()=&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Value was hello"&lt;/span&gt;); } 
  },
  { x =&amp;gt; x.StartsWith(&lt;span style="color: #a31515"&gt;"h"&lt;/span&gt;), 
     ()=&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"value started with h, but wasn't hello"&lt;/span&gt;); } 
  },
  { &lt;span style="color: green"&gt;// default
     &lt;/span&gt;() =&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"No match - Fallthrough"&lt;/span&gt;); } 
  }
};

&lt;span style="color: green"&gt;// how about a case insensitive comparison? switch (switchValue.ToLower()) ?
// or...

&lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Switch&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(switchValue, &lt;span style="color: #2b91af"&gt;StringComparer&lt;/span&gt;.InvariantCultureIgnoreCase)
{
  { &lt;span style="color: #a31515"&gt;"HOUSE"&lt;/span&gt;, ()=&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Value was house"&lt;/span&gt;); } },
  { x =&amp;gt; x.StartsWith(&lt;span style="color: #a31515"&gt;"H"&lt;/span&gt;, &lt;span style="color: #2b91af"&gt;StringComparison&lt;/span&gt;.InvariantCultureIgnoreCase), &lt;br /&gt;     ()=&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"value started with h, but wasn't house"&lt;/span&gt;); } &lt;br /&gt;  },
  { () =&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"No match - Fallthrough"&lt;/span&gt;); } }
};

&lt;span style="color: green"&gt;// what about an expression equivalent?

&lt;/span&gt;&lt;span style="color: blue"&gt;string &lt;/span&gt;val = &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Switch&lt;/span&gt;&amp;lt;&lt;span style="color: blue"&gt;string&lt;/span&gt;, &lt;span style="color: blue"&gt;string&lt;/span&gt;&amp;gt;(switchValue)
{
   { &lt;span style="color: #a31515"&gt;"hello"&lt;/span&gt;, ()=&amp;gt; &lt;span style="color: #a31515"&gt;"Value was hello" &lt;/span&gt;},
   { x =&amp;gt; x.StartsWith(&lt;span style="color: #a31515"&gt;"h"&lt;/span&gt;), ()=&amp;gt; &lt;span style="color: #a31515"&gt;"value started with h, but wasn't hello" &lt;/span&gt;},
   { () =&amp;gt; &lt;span style="color: #a31515"&gt;"No match - Fallthrough" &lt;/span&gt;}
};

&lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(val);

&lt;span style="color: green"&gt;// what about things other than strings?

&lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime &lt;/span&gt;today = &lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;.Today;

&lt;span style="color: green"&gt;// can't switch (today)... but we can Switch&amp;lt;DateTime&amp;gt; on it:

&lt;/span&gt;&lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;Switch&lt;/span&gt;&amp;lt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;&amp;gt;(today)
{
   { &lt;span style="color: blue"&gt;new &lt;/span&gt;&lt;span style="color: #2b91af"&gt;DateTime&lt;/span&gt;(2009, 01, 01), () =&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Happy 2009!"&lt;/span&gt;); } },
   { day =&amp;gt; day.Day == 1, &lt;br /&gt;      () =&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"It's the first day of a new month"&lt;/span&gt;); } &lt;br /&gt;   },
   { () =&amp;gt; { &lt;span style="color: #2b91af"&gt;Console&lt;/span&gt;.WriteLine(&lt;span style="color: #a31515"&gt;"Nothing happening today"&lt;/span&gt;); } }
};&lt;/pre&gt;

&lt;p&gt;I should point out that I do have an implementation of the Switch class used here (well, technically Switch classes, and a bonus point to anyone paying enough attention to spot the second one), and it works exactly as shown, but I've less of an urge to share the grubby details of the implementation than to show the twisted client code it enables.&lt;/p&gt;

&lt;p&gt;Next time on Dangerous Ideas in C#, we'll see what havoc can be wrought with 'yield return' statements.&lt;/p&gt;&lt;img src="http://blogs.ipona.com/james/aggbug/8494.aspx" width="1" height="1" /&gt;</description>
            <dc:creator>James Hart</dc:creator>
            <guid>http://blogs.ipona.com/james/archive/2008/05/23/Dangerous-Ideas-in-C-No.-1-A-Better-Switch.aspx</guid>
            <pubDate>Fri, 23 May 2008 08:57:57 GMT</pubDate>
            <wfw:comment>http://blogs.ipona.com/james/comments/8494.aspx</wfw:comment>
            <comments>http://blogs.ipona.com/james/archive/2008/05/23/Dangerous-Ideas-in-C-No.-1-A-Better-Switch.aspx#feedback</comments>
            <slash:comments>3</slash:comments>
            <wfw:commentRss>http://blogs.ipona.com/james/comments/commentRss/8494.aspx</wfw:commentRss>
            <trackback:ping>http://blogs.ipona.com/james/services/trackbacks/8494.aspx</trackback:ping>
        </item>
    </channel>
</rss>