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

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

Left by Guy Murphy on Jan 05, 2009 4:43 PM

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

Requesting Gravatar...
This bugged me so I had to play with it some myself... the following if you added a littel polish is in the ballpark I believe...

public class Switch<T>: IEnumerable {

private T _switchValue;
private bool _block;

public Switch (T switchValue) {
_block = false;
_switchValue = switchValue;
}

public void Add (Predicate<T> p, Action<T> a) {
if (!_block && p.Invoke(_switchValue)) {
a.Invoke(_switchValue);
_block = true;
}
}

#region IEnumerable Members
public IEnumerator GetEnumerator () {
throw new NotImplementedException();
}
#endregion
}
Left by Guy Murphy on Jan 07, 2009 12:53 PM

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

Requesting Gravatar...
I think this is a problem you get when you have the marketing departments running the show. ASP.NET MVC is the same thing. The popularity of Ruby On Rails forced microsoft to play catch up, but its kind of a regression because it reminds me of the original ASP
Left by Bonus gioco casinò online on Mar 27, 2010 10:56 AM

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

Requesting Gravatar...
TY :p
Left by watches replicas on Apr 29, 2010 3:02 AM

Your comment:

 (will show your gravatar)
 
Please add 4 and 7 and type the answer here: