Code Focused

Cool Case Clauses in Visual Basic and C#

Each language treats case clauses differently, but there's a way you can make them less boring in C#.

Case clauses in Visual Basic are cool. You can load them up with all kinds of expressions and method calls, allowing you to fine-tune your criteria:

Select Case patrons
  Case 1, 2
    ' ----- Small table: based on item list
  Case 3 To 6
    ' ----- Medium table: based on range
  Case ReturnSeven()
    ' ----- Large table: based on method call
  Case Is > 7
    ' ----- Extra large table: based on comparison
End Select

In C#, things aren't so cool. Each case clause is limited to a single constant value; no expressions, no methods, no comparison operators. If you want to process complex expressions like those in Visual Basic, you would normally use a series of if statements. You could retain the case clauses, but only by first processing the test value through some if-statement equivalent:

string testValue =
  (new int[] { 1, 2 }).Contains(patrons) ? "S" :
  patrons >= 3 & patrons <= 6            ? "M" :
  patrons == ReturnSeven()               ? "L" :
  patrons > 7                            ? "XL" :
  "";

switch (testValue)
{
  case "S":
    // ----- Small table code here.
    break;
  case "M":
    // ----- Medium table code here.
    break;
  case "L":
    // ----- Large table code here.
    break;
  case "XL":
    // ----- Extra large table code here.
    break;
}

But what if you wanted to be as cool as those Select Case users? Can you combine boring C# switch statements with conditional processing statements that are as feature-rich as those in Visual Basic? Perhaps by combining generics, lambda expressions and LINQ? Why, yes, yes you can. Let's generate the test variable for the switch statement by using LINQ to process a collection of conditional lambda expressions.

In this make-believe restaurant example, the goal has been to determine how large of a table to provide to a group of hungry patrons. To determine that, you need criteria functions that each accepts a customer count and indicates, true or false, whether the criteria for that table size is met. Let's create a delegate -- a method template -- that will help provide consistency in all criteria functions:

private delegate bool TableCountMatch(int eaters);

Next, you need a place to store all of these criteria functions, linking them to a target table size. You could build a custom generic class that tracks criteria functions and table sizes in tandem. But lucky for you, there's already a collection type that includes room for two values -- a dictionary:

Dictionary<TableCountMatch, string> testCases =
  new Dictionary<TableCountMatch, string>();

Dictionary collections require that the "key" part of the dictionary be unique. Because each criteria function will be its own unique analysis system, you'll use that for the unique key, storing the associated table size as the dictionary value:

testCases.Add((eaters) => (new int[] { 1, 2 }).Contains(eaters), "S");
testCases.Add((eaters) => eaters >= 3 & eaters <= 6,             "M");
testCases.Add((eaters) => eaters == ReturnSeven(),               "L");
testCases.Add((eaters) => eaters > 7,                            "XL");

Now you have a collection of criteria functions, stored as delegates, and matching table sizes that get spit out when a function returns true for a specific customer count. You just need the tool that does the spitting, and LINQ is good for that:

string testValue =
  (from scanTest in testCases
  where scanTest.Key(patrons)
  select scanTest.Value).First();

switch (testValue)
{
  case "S":
    // ----- And so on...

The query processes each entry in the dictionary, passing the patron count to the "key" function delegate, and returning the table size "value" when a function returns true. In case multiple criteria functions match the customer count, it's a good idea to wrap the query in an extension method that returns just the first match.

This code isn't perfect. Because the LINQ query checks all entries in the criteria dictionary, each entry will evaluate, even when an earlier criteria returns true. Allowing every criteria function to evaluate might have undesirable side effects. And yet, it's cool, and what's programming about if you can't enjoy a little cool from time to time?

About the Author

Tim Patrick has spent more than thirty years as a software architect and developer. His two most recent books on .NET development -- Start-to-Finish Visual C# 2015, and Start-to-Finish Visual Basic 2015 -- are available from http://owanipress.com. He blogs regularly at http://wellreadman.com.

comments powered by Disqus

Featured

  • IDE Irony: Coding Errors Cause 'Critical' Vulnerability in Visual Studio

    In a larger-than-normal Patch Tuesday, Microsoft warned of a "critical" vulnerability in Visual Studio that should be fixed immediately if automatic patching isn't enabled, ironically caused by coding errors.

  • Building Blazor Applications

    A trio of Blazor experts will conduct a full-day workshop for devs to learn everything about the tech a a March developer conference in Las Vegas keynoted by Microsoft execs and featuring many Microsoft devs.

  • Gradient Boosting Regression Using C#

    Dr. James McCaffrey from Microsoft Research presents a complete end-to-end demonstration of the gradient boosting regression technique, where the goal is to predict a single numeric value. Compared to existing library implementations of gradient boosting regression, a from-scratch implementation allows much easier customization and integration with other .NET systems.

  • Microsoft Execs to Tackle AI and Cloud in Dev Conference Keynotes

    AI unsurprisingly is all over keynotes that Microsoft execs will helm to kick off the Visual Studio Live! developer conference in Las Vegas, March 10-14, which the company described as "a must-attend event."

  • Copilot Agentic AI Dev Environment Opens Up to All

    Microsoft removed waitlist restrictions for some of its most advanced GenAI tech, Copilot Workspace, recently made available as a technical preview.

Subscribe on YouTube