Dangerous Ideas in C# No. 1: A 'Better' Switch

Switch statements are rubbish. Only work on strings and numbers. Require an exact match value.

Let’s abuse, oh, to pick a C# feature at random, collection initialisers, and use it to make them better!

string switchValue = "house";

switch (switchValue)
{
   case "hello":
      Console.WriteLine("Value was hello");
      break;
   // But how can we handle, say, all other strings that start with h?
   default:
      Console.WriteLine("No match - Fallthrough");
      break;
}

// here’s one way:
new Switch<string>(switchValue)
{
  { "hello", 
     ()=> { Console.WriteLine("Value was hello"); } 
  },
  { x => x.StartsWith("h"), 
     ()=> { Console.WriteLine("value started with h, but wasn't hello"); } 
  },
  { // default
     () => { Console.WriteLine("No match - Fallthrough"); } 
  }
};

// how about a case insensitive comparison? switch (switchValue.ToLower()) ?
// or...

new Switch<string>(switchValue, StringComparer.InvariantCultureIgnoreCase)
{
  { "HOUSE", ()=> { Console.WriteLine("Value was house"); } },
  { x => x.StartsWith("H", StringComparison.InvariantCultureIgnoreCase), 
()=> { Console.WriteLine("value started with h, but wasn't house"); }
}, { () => { Console.WriteLine("No match - Fallthrough"); } } }; // what about an expression equivalent? string val = new Switch<string, string>(switchValue) { { "hello", ()=> "Value was hello" }, { x => x.StartsWith("h"), ()=> "value started with h, but wasn't hello" }, { () => "No match - Fallthrough" } }; Console.WriteLine(val); // what about things other than strings? DateTime today = DateTime.Today; // can't switch (today)... but we can Switch<DateTime> on it: new Switch<DateTime>(today) { { new DateTime(2009, 01, 01), () => { Console.WriteLine("Happy 2009!"); } }, { day => day.Day == 1,
() => { Console.WriteLine("It's the first day of a new month"); }
}, { () => { Console.WriteLine("Nothing happening today"); } } };

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.

Next time on Dangerous Ideas in C#, we'll see what havoc can be wrought with 'yield return' statements.

Print | posted on Friday, May 23, 2008 9:57 AM

Comments on this post

# re: Dangerous Ideas in C# No. 1: A 'Better' Switch

Requesting Gravatar...
That's just evil. Clever and cool, but evil all the same.
Left by Dave on May 23, 2008 11:23 AM

# re: Dangerous Ideas in C# No. 1: A 'Better' Switch

Requesting Gravatar...
new Switch<string, string> ?

Where's the second string it's matching?
Left by Dan on May 23, 2008 12:29 PM

# re: Dangerous Ideas in C# No. 1: A 'Better' Switch

Requesting Gravatar...
Switch<string, string> - the second string would be the return type for those lambda expressions. And you may have the bonus point for identifying the second type :)

Actually, it really indicates the fundamental problem with using collection initialisers for this job: you can't rely on type inferencing to fill in these parameters for you, as you could if Switch were a generic method rather than a generic type with a twisted construction convention.

But there is something unique to collection initialisers that does make them uniquely suited to this...
Left by James on May 23, 2008 2:32 PM

Your comment:

 (will show your gravatar)
 
Please add 1 and 8 and type the answer here: