© Sylverarts Vectors/Shutterstock.com
Kompakter und prägnanter C#-Code durch Pattern Matching

C# Pattern Matching Inside Out


Erstmals in C# 7 eingeführt, wurde Pattern Matching seitdem weiterentwickelt. Auch in der aktuellen Version C# 9 wurde das Sprachkonstrukt mit Neuerungen bedacht. Es soll dabei helfen, kompakteren Code zu schreiben. In diesem Artikel wird demonstriert, wie Pattern Matching sinnvoll eingesetzt werden kann.

Eines vorweg: Alles, was man mit Pattern Matching machen kann, konnte man mit anderen Mechanismen bisher auch schon in C# erledigen. Bei Pattern Matching geht es darum, dass man Code kompakter und aussagekräftiger schreiben kann. Wir dürfen nicht vergessen, dass Code viel häufiger gelesen als geschrieben wird. Insofern ist es für eine Programmiersprache wichtig, dass man als Entwicklerin oder Entwickler Sprachkonstrukte zur Verfügung hat, mit denen man seine Intention gut ausdrücken kann. Wenn das gelingt, wird die spätere Wartung und Erweiterung des Codes nicht schwerfallen. Außerdem erspart man sich durch die von Haus aus hohe Aussagekraft des Codes eine Menge Dokumentationsarbeit.

Video

Der Autor dieses Artikels hat zum Thema C# Pattern Matching Inside Out auf der BASTA! 2020 einen Vortrag gehalten, in dem das Thema und zum Teil auch die Beispiele dieses Artikels im Detail erklärt wurden. Interessierte Leserinnen und Leser finden das Video auf YouTube: https://youtu.be/9HUf1-MfHJo.

Historie

C# lernte die ersten Pattern-Matching-Funktionen in C# 7. Seitdem wurde diese Sprachfunktion konsequent weiterentwickelt. Mit jeder erschienenen Version lernte C# neue Tricks, auch in der aktuell vorliegenden Version 9 kamen wieder Neuerungen dazu. In diesem Artikel möchte ich die Möglichkeiten von Pattern Matching nicht strikt in der Reihenfolge ihres Erscheinens in C# vorstellen, sondern eine Reise von den einfachen Anwendungsfällen bis hin zu den mächtigeren und daher komplexeren Konstruktionen anbieten.

Beispielcode

Dieser Artikel enthält viele Codebeispiele, da man ein C#-Sprachkonstrukt wie Pattern Matching meiner Ansicht nach am besten anhand von Beispielen erklärt. Wer mit dem Beispielcode experimentieren möchte, der kann den jeweiligen Code in eine .NET-5-/C#-9-Konsolenanwendung kopieren. Alle Listings können für sich allein ausprobiert werden. Um den Beispielcode kurz und prägnant zu halten, sind die darin zum Teil verwendeten Hilfstypen (HeroType, HeroTypeCategory, VoughtEmployeeType, Person und Hero) nur in Listing 3 enthalten. Sie werden in den darauffolgenden Listings ebenfalls verwendet, werden dort aber nicht jedes Mal wiederholt.

Natürlich brauchen Sie den Code nicht abzutippen. Ich habe ein GitHub Gist [1] erstellt, das alle Codebeispiele enthält, die Sie von dort kopieren können. Die oben erwähnten Hilfstypen sind in den Gists im Gegensatz zu den Listings dieses Artikels jedes Mal enthalten, müssen also nicht manuell kopiert werden.

Wer ganz genau wissen möchte, was hinter den Kulissen passiert, dem empfehle ich, die generierten Assemblies mit dnSpy [1] zu disassemblieren und sich den generierten IL-Code anzusehen.

Constant Pattern

Wir starten mit dem einfachsten Pattern, dem Constant Pattern. Wir können damit einen Ausdruck mit einer Konstanten vergleichen. Das ergibt auf den ersten Blick keinen Sinn, schließlich hat C# den Equality Operator (==). Der Sinn erschließt sich, wenn man sich in Listing 1 das zweite Beispiel ansieht, bei dem eine Zahl mit einer Variablen vom Typ object verglichen wird. Hier hätte man bisher .Equals() schreiben müssen. Der is-Operator erkennt das automatisch und verwendet die jeweils richtige Form der Prüfung auf Gleichheit. Das Constant Pattern für sich allein genommen wird bei Ihnen wahrscheinlich keine große Begeisterung auslösen. Es ist aber eine Grundlage, auf der komplexere Patterns aufbauen, auf die wir später im Artikel eingehen werden.

Listing 1: Constant Pattern

using static System.Console; // We can simply replace == with is. Doesn’t make much sense, though. int someNumber = 42; if (someNumber is 42) WriteLine("Some number is 42"); // Situation changes when we change the type to object. object something = 42; // The following statement would not work (you cannot use == with // object and int). We need to use `Equals` instead. // if (something == 42) ... if (something.Equals(42)) WriteLine("Something is 42"); // Now we can write this much nicer with Constant Patterns: if (something is 42) WriteLine("Something is 42");

Var Pattern

Auch das zweite Pattern, das ich hier vorstellen möchte, ist für sich genommen ziemlich uninteressant: das Var Pattern. Kombiniert man es aber mit anderen Sprachkonstrukten, insbesondere mit switch, ergeben sich ganz neue Möglichkeiten. Listing 2 zeigt das an einem Beispiel.

Listing 2: Var Pattern

using System; using static System.Console; // The var pattern doesn’t make much sense when used on its own. int someNumber = 42; if (someNumber is var x) WriteLine(x); // It enables new possibilities in combination with other // language features, in particular with switch. switch (someNumber) { case 41: WriteLine("fourtyone"); break; case 43: WriteLine("fourtythree"); break;  case var n when n % 2 == 0: WriteLine("even"); break; default: throw new NotImplementedException(""); }

Type Pattern

Das Type Pattern ist meiner Erfahrung nach eines der nützlichsten Patterns, das ich häufig auch in der Praxis verwende. Es ersetz...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Teams

Für Firmen haben wir individuelle Teamlizenzen. Wir erstellen Ihnen gerne ein passendes Angebot.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang