A better switch with Lambdas in .NET, Part 1

I don’t know which programming language you belong to, or which is the best language you have been working on… but one of the best syntax that I think you should be proudly using is the very old switch / case operators. The Switch/case operator gives an clean and clear look on what the code is intended to do and makes a lot of things really easy and maintainable. If you have 100’s or logical operations as a developers, you might be always trying to define an enumeration for all these operations and trying out the switch/case, not only because it gives a better readability, but also it is very easy to maintain. This gives a clear edge to a programmer to use Switch / case more often than if – else statements.

But if you have been using switch statements for a while, there are a lot of limitations on the switch -case statements :

  1. It would unable to provide switching when the logical operators are not discrete.
  2. It cannot be used when the switcher is a type other than string, integer, enum or other constants.
  3. It cannot ignore cases or even ordinal checks

Therefore, even liking the switch statements, people are inclined to use if-else more often than they do with switch cases.

But with the introduction to Lamda expressions, it opens up a lot of new ways to define things that you have been forced to do in another way. With giving everything to lambda the code would look easier to use and even would be better understandable. Rx Team recently introduced Interactive Extensions (Ix) which has replaced a lot of existing logic to a lambda implementation counterpart.

This made me think, why cant we redefine the switch/case in a better way, such that every cases is turned into a lambda (or a anonymous method) and add a lot of functionality to it. With this thought, I went ahead and tried few switches that you can also use in your code.

 Switch / Case with Lambdas : 

Let us try to implement how a normal switch-case would look like when used in terms of Lambda expressions.

public static class SimpleSwitch
{
public class CaseInfo
{
public T Case { get; set; }
public Action TargetAction { get; set; }
public bool IsDefault { get; set; }
}

public static void Me(T source, params CaseInfo[] cases)
{
CaseInfo defaultCase = null;
bool isTargetActionTaken = false;
foreach (var entry in cases)
{
if (entry.IsDefault)
defaultCase = entry;

if (!entry.IsDefault && entry.Case.Equals(source))
{
entry.TargetAction(source);
isTargetActionTaken = true;
break;
}
}
if (!isTargetActionTaken && defaultCase != null)
defaultCase.TargetAction(source);

}
public static CaseInfo Case(T source, Action action)
{
return new CaseInfo { TargetAction = x => action(), Case = source };
}
public static CaseInfo Default(Action action)
{
return new CaseInfo { TargetAction = x => action(), IsDefault = true };
}
}

Now if you look into the code closely, this makes an implementation of a normal switch/case statement. Yes, I agree, there are lot of things that aren’t taken care of with this code (like duplicate cases, fallback cases etc), but it could basically give you an idea on how this could look like.

To demonstrate the code above, we have declared a Generic Type CaseInfo which takes T as generic parameter. We could have easily make CaseInfo with fixed type, but we did just to ensure we can pass int or enum with the same class. We defined a static method Me which will allow you to define the switch case, where T would be the source which need to be checked to each of the cases and TargetAction gets invoked. We also provided an implementation of Default case which will check whether the source matches any of the cases, or otherwise we call the Default case (the one with IsDefault is turned on).

Let us try to call this switcher from code to see how it works.


static void Main(string[] args)
{
string strSource = "Abhishek";
SimpleSwitch.Me<string>(strSource,
new SimpleSwitch.CaseInfo<string>
{
Case = "Abhijit",
TargetAction = e =>
{
Console.WriteLine("Abhijit:" + e);
}
},
new SimpleSwitch.CaseInfo<string>
{
Case = "Abhishek",
TargetAction = e =>
{
Console.WriteLine("Abhishek:" + e);
}
},
new SimpleSwitch.CaseInfo<string>
{
Case = "Anoop",
TargetAction = e =>
{
Console.WriteLine("Anoop:" + e);
}
},
new SimpleSwitch.CaseInfo<string>
{
IsDefault = true,
TargetAction = e =>
{
Console.WriteLine("Default:" + e);
}
});

Console.ReadKey(true);
}

In the above code, you can see, if we feed in the external variable strSource with the cases, it will automatically detect the appropriate Source and call the Case which it intended. If you run this code, the Console will print Abhishek: Abhishek.

You can test with different strings for strSource with the same switch and see if it matches with any of the case, it will pick it up, or otherwise it will pick the Default case, which prints the source with Default.

With this switcher, you can also use int / enums as well. Let us check that too.

public enum SwitchEnum
{
Abhishek, Abhijit, Anoop
}
static void Main(string[] args)
{
SwitchEnum strSource = SwitchEnum.Abhijit;
SimpleSwitch.Me(strSource,
new SimpleSwitch.CaseInfo
{
Case = SwitchEnum.Abhijit,
TargetAction = e =>
{
Console.WriteLine("Abhijit:" + e);
}
},
new SimpleSwitch.CaseInfo
{
Case = SwitchEnum.Abhishek,
TargetAction = e =>
{
Console.WriteLine("Abhishek:" + e);
}
},
new SimpleSwitch.CaseInfo
{
Case = SwitchEnum.Anoop,
TargetAction = e =>
{
Console.WriteLine("Anoop:" + e);
}
},
new SimpleSwitch.CaseInfo
{
IsDefault = true,
TargetAction = e =>
{
Console.WriteLine("Default:" + e);
}
});

Console.ReadKey(true);
}

Now with almost the same code, and replacing the Type T with to an enum or other random types, we can use this similarly. BTW, you can also use this switch to case on any other type that implements Equals operator inside it. If you don’t overload Equals in your type for which Type has been used, it will automatically use ReferenceEquals to check the Cases. 

Conclusion

You might be already started thinking why is it at all required, or even we need when we already have a switch / case implemented in the language. Well, we can add a lot of things with this switcher to complement the power of lambda expressions so that we do not need to use if-else in those cases. What if we want to compare normal objects other than what is supported. Let us see that in my next post.

Stay tune… Happy programming.  🙂

I hope you like my post.

Abhishek Sur

Abhishek Sur is a Microsoft MVP since year 2011. He is an architect in the .NET platform. He has profound theoretical insight and years of hands on experience in different .NET products and languages. He leads the Microsoft User Group in Kolkata named KolkataGeeks, and regularly organizes events and seminars in various places for spreading .NET awareness. He is associated with the Microsoft Insider list on WPF and C#, and is in constant touch with product group teams. He blogs at http://www.abhisheksur.com His Book : Visual Studio 2012 and .NET 4.5 Expert Development Cookbook. Follow Abhishek at Twitter : @abhi2434