Code Focused

Pattern Matching in C# 7.0 Case Blocks

Welcome to the 21st century, C#, now that case blocks support a variety of pattern-matching formats.

Switch statements and the case blocks they contain have been a mainstay of C-language flow-control syntax since the initial incarnation of the language back in the 1970s. C# inherited the overall switch statement constructs from C, including its mundane constant-based selection process. Except for the requirement that a break statement appear at the end of each case block, little has changed in four decades. 

Visual Basic, by contrast, sports supercharged Case blocks that enable complex comparisons that are far more interesting than simple lists of constants:

Select Case age
  Case 50
    ageBlock = "the big five-oh"
  Case 80, 81, 82, 83, 84, 85, 86, 87, 88, 89
    ageBlock = "octogenarian"
  Case 90 To 99
    ageBlock = "nonagenarian"
  Case Is >= 100
    ageBlock = "centenarian"
  Case Else
    ageBlock = "just old"
End Select

C# 7.0, as part of Visual Studio 2017, brings switch statements into the 21st century, thanks to the new pattern-matching features added to case blocks. Three distinct matching formats are now possible. (Be aware that all samples listed in this article use the Visual Studio 2017 Release Candidate, and some elements might change before the final release.) The first format is the same tried-and-true constant syntax that has been around since the first C# release:

switch (age)
{
  case 50:
    ageBlock = "the big five-oh";
    break;
  case 80:
  case 81:
  case 82:
  // ... and so on ...
  case 89:
    ageBlock = "octogenarian";
    break;
  default:
    ageBlock = "just old";
    break;
}

The new type pattern enables matches based on a specific class or structure. These expressions include a type name followed by a new variable instance that can be accessed within the code of the matching case block. Null instances never match these expressions, and instead must be handled (if desired) using a null-constant matching block:

// ----- Assume that spaceItem is of type SpaceType,
//       and that Planet and Star derive from SpaceType.
switch (spaceItem)
{
  case Planet p:
    if (p.Type != PlanetType.GasGiant)
      LandSpacecraft(p);
    break;
  case Star s:
    AvoidHeatSource(s);
    break;
  case null:
    // ----- If spaceItem is null, processing falls here,
    //       even if it is a Planet or Star null instance.
    break;
  default:
    // ----- Anything else that is not Planet, Star, or null.
    break;
}

One implication of this syntax is that switch statements are no longer limited to core data types like integers and strings. You can include variables or expressions of any .NET type within both the switch statement and the case block expressions. Also, null is now a valid constant expression. It catches null reference-type objects, even if those same types are mentioned in a non-null fashion in other blocks.

The third format, known as var patterns, uses the var keyword, and simply copies the source test variable or expression into a new, named variable:

switch (testVariable)
{
  case var blockVariable:
    // ----- Use blockVariable here as needed.
    break;
}

This seems a bit pointless, until you add the when clause, also new to case blocks in C# 7.0. When attached to the end of a case block expression, the when keyword enables access to Visual Basic-style Case block comparisons:

switch (age)
{
  case 50:
    ageBlock = "the big five-oh";
    break;
  case var testAge when (new List<int>()
      { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89 }).Contains(testAge):
    ageBlock = "octogenarian";
    break;
  case var testAge when ((testAge >= 90) & (testAge <= 99)):
    ageBlock = "nonagenarian";
    break;
  case var testAge when (testAge >= 100):
    ageBlock = "centenarian";
    break;
  default:
    ageBlock = "just old";
    break;
}

The when clause also works with type-style patterns:

switch (spaceItem)
{
  case Planet p when (p.Type != PlanetType.GasGiant):
    LandSpacecraft(p);
    break;
  case Planet p:
    // ----- Gas giants fall here.
    break;

Visual Studio 2015 and its associated C# 6.0 release included a similar when-clause pattern as part of the structured error-handling system:

// ----- Assumes a Boolean variable named hasOtherErrors
try
{
  // ----- Error-prone code here.
}
catch (Exception ex) when (hasOtherErrors == true)
{
  // ----- This isn't the first error.
}
catch (Exception ex)
{
  // ----- First-time error.
}

When logic branching requires anything more than a simple value-type comparison, C# developers have routinely reached for if-else statements to guide data processing. With the new case-block enhancements in C# 7.0 and Visual Studio 2017, switch statements have now become a reasonable option for expression-rich flow-control processing.

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

  • VS Code Copilot Previews New GPT-4o AI Code Completion Model

    The 4o upgrade includes additional training on more than 275,000 high-quality public repositories in over 30 popular programming languages, said Microsoft-owned GitHub, which created the original "AI pair programmer" years ago.

  • Microsoft's Rust Embrace Continues with Azure SDK Beta

    "Rust's strong type system and ownership model help prevent common programming errors such as null pointer dereferencing and buffer overflows, leading to more secure and stable code."

  • Xcode IDE from Microsoft Archrival Apple Gets Copilot AI

    Just after expanding the reach of its Copilot AI coding assistant to the open-source Eclipse IDE, Microsoft showcased how it's going even further, providing details about a preview version for the Xcode IDE from archrival Apple.

  • Introduction to .NET Aspire

    Two Microsoft experts will present on the cloud-native application stack designed to simplify the development of distributed systems in .NET at the Visual Studio Live! developer conference coming to Las Vegas next month.

  • Microsoft Previews Copilot AI for Open-Source Eclipse IDE

    Catering to Java jockeys, Microsoft is yet again expanding the sprawling reach of its Copilot-branded AI assistants, previewing a coding tool for the open-source Eclipse IDE.

Subscribe on YouTube

Upcoming Training Events