Hinweis
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, sich anzumelden oder das Verzeichnis zu wechseln.
Für den Zugriff auf diese Seite ist eine Autorisierung erforderlich. Sie können versuchen, das Verzeichnis zu wechseln.
Mit dem Musterabgleich können Sie Funktionen für Typen hinzufügen, die in anderen Bibliotheken definiert sind, ohne diese Typen zu ändern. Ein weiterer Verwendungszweck für Muster ist die Erstellung von Funktionalität, die Ihre Anwendung erfordert, und die keine grundlegende Funktion des erweiterten Typs ist.
In diesem Tutorial erfahren Sie, wie:
- Erkennen von Situationen, in denen ein Musterabgleich verwendet werden soll.
- Verwenden von Musterabgleichausdrücken, um Verhalten auf Grundlage von Typen und Eigenschaftswerten zu implementieren.
- Kombinieren des Musterabgleichs mit anderen Verfahren, um vollständige Algorithmen zu erstellen.
Prerequisites
- Das neueste .NET SDK
- Visual Studio Code Editor
- Das C# DevKit
Installationsanweisungen
Verwenden Sie auf Windows diese WinGet-Konfigurationsdatei, um alle erforderlichen Komponenten zu installieren. Wenn Sie bereits etwas installiert haben, überspringt WinGet diesen Schritt.
- Laden Sie die Datei herunter, und doppelklicken Sie, um sie auszuführen.
- Lesen Sie den Lizenzvertrag, geben Sie yein, und wählen Sie Geben Sie ein, wenn Sie zur Annahme aufgefordert werden.
- Wenn Sie in Ihrer Taskleiste eine blinkende Eingabeaufforderung für die Benutzerkontensteuerung (User Account Control, UAC) erhalten, können Sie die Installation fortsetzen.
Auf anderen Plattformen müssen Sie jede dieser Komponenten separat installieren.
- Laden Sie das empfohlene Installationsprogramm von der .NET SDK-Downloadseite herunter , und doppelklicken Sie, um es auszuführen. Die Downloadseite erkennt Ihre Plattform und empfiehlt das neueste Installationsprogramm für Ihre Plattform.
- Laden Sie das neueste Installationsprogramm von der Startseite Visual Studio Code herunter, und doppelklicken Sie darauf, um es auszuführen. Diese Seite erkennt auch Ihre Plattform, und der Link sollte für Ihr System korrekt sein.
- Klicken Sie auf der Erweiterungsseite C# DevKit auf die Schaltfläche "Installieren". Dadurch wird Visual Studio-Code geöffnet und gefragt, ob Sie die Erweiterung installieren oder aktivieren möchten. Wählen Sie "Installieren" aus.
Szenarien für den Musterabgleich
Moderne Entwicklung umfasst häufig die Integration von Daten aus mehreren Quellen und die Darstellung von aus diesen Daten gewonnenen Informationen und Einblicken in einer einzelnen zusammenhängenden Anwendung. Möglicherweise steuern Sie und Ihr Team nicht die Datentypen für eingehende Daten.
Der klassische objektorientierte Entwurfsansatz sieht die Erstellung von Typen in Ihrer Anwendung vor, die jeden Datentyp aus diesen mehreren Datenquellen darstellen. Anschließend arbeitet Ihre Anwendung mit diesen neuen Typen zusammen, erstellt Vererbungshierarchien, erstellt virtuelle Methoden und implementiert Abstraktionen. Diese Verfahren funktionieren, und manchmal sind sie die besten Tools. In anderen Fällen können Sie weniger Code schreiben. In einigen Fällen kann das Trennen von Daten von den verwendeten Vorgängen das Lesen des Codes vereinfachen.
In diesem Lernprogramm erstellen und untersuchen Sie eine Anwendung, die eingehende Daten aus mehreren externen Quellen für ein einzelnes Szenario empfängt. Sie sehen, wie Pattern Matching eine effiziente Möglichkeit zum Nutzen und Verarbeiten dieser Daten in einer Weise bietet, die nicht Teil des ursprünglichen Systems war.
Berücksichtigen Sie eine große Metropolregion, die Mautgebühren und Stoßzeitgebühren verwendet, um den Verkehr zu verwalten. Sie schreiben eine Anwendung, die Mautgebühren für ein Fahrzeug basierend auf seinem Typ berechnet. In späteren Verbesserungen wird die Preisgestaltung auf Basis der Anzahl der Fahrzeuginsassen integriert. Bei weiteren Verbesserungen kommt die Preisgestaltung auf Basis der Tageszeit und des Wochentages hinzu.
Aus dieser kurzen Beschreibung können Sie schnell eine Objekthierarchie skizzieren, um dieses System zu modellieren. Ihre Daten stammen jedoch aus mehreren Quellen wie anderen Fahrzeugregistrierungssystemen. Diese Systeme bieten verschiedene Klassen zum Modellieren dieser Daten, und diese Systeme verwenden kein einzelnes Objektmodell. In diesem Lernprogramm verwenden Sie diese vereinfachten Klassen, um die Fahrzeugdaten aus diesen externen Systemen zu modellieren, wie im folgenden Code gezeigt:
namespace ConsumerVehicleRegistration
{
public class Car
{
public int Passengers { get; set; }
}
}
namespace CommercialRegistration
{
public class DeliveryTruck
{
public int GrossWeightClass { get; set; }
}
}
namespace LiveryRegistration
{
public class Taxi
{
public int Fares { get; set; }
}
public class Bus
{
public int Capacity { get; set; }
public int Riders { get; set; }
}
}
Sie können den Startercode aus dem Repository dotnet/samples auf GitHub herunterladen. Sie können sehen, dass die Fahrzeugklassen aus verschiedenen Systemen stammen und sich in verschiedenen Namespaces befinden. Sie können keine andere gemeinsame Basisklasse als System.Object verwenden.
Entwürfe für Musterabgleich
Das in diesem Lernprogramm verwendete Szenario hebt die Arten von Problemen hervor, die sich mit Mustervergleich gut lösen lassen:
- Die Objekte, mit denen Sie arbeiten müssen, befinden sich nicht in einer Objekthierarchie, die Ihren Zielen entspricht. Möglicherweise arbeiten Sie mit Klassen, die Teil von nicht verknüpften Systemen sind.
- Die Funktionalität, die Sie hinzufügen, ist nicht Teil der Kernabstraktion für diese Klassen. Die für ein Fahrzeug gezahlte Maut ändert sich für verschiedene Arten von Fahrzeugen, aber die Maut ist keine Kernfunktion des Fahrzeugs.
Wenn die Form der Daten und die mit diesen Daten durchgeführten Operationen nicht zusammen beschrieben werden, erleichtern die Musterabgleichfunktionen in C# die Arbeit mit ihnen.
Implementieren der grundlegenden Mautberechnungen
Die grundlegendsten Mautberechnungen basieren nur auf dem Fahrzeugtyp:
- Ein
Carkostet 2,00 US-Dollar. - Ein
Taxikostet 3,50 US-Dollar. - Ein
Buskostet 5,00 US-Dollar. - A
DeliveryTruckist $10,00.
Erstellen Sie eine neue TollCalculator-Klasse, und implementieren Sie einen Musterabgleich nach dem Fahrzeugtyp, um den Mautbetrag zu ermitteln. Im folgenden Codebeispiel wird die ursprüngliche Implementierung der TollCalculator-Klasse veranschaulicht.
using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;
namespace Calculators;
public class TollCalculator
{
public decimal CalculateToll(object vehicle) =>
vehicle switch
{
Car c => 2.00m,
Taxi t => 3.50m,
Bus b => 5.00m,
DeliveryTruck t => 10.00m,
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
}
Der vorherige Code verwendet einen switch-Ausdruck (nicht zu verwechseln mit einer switch-Anweisung), der das Deklarationsmuster testet. Ein Switch-Ausdruck beginnt mit der Variablen – vehicle im vorangehenden Code – gefolgt vom switch-Schlüsselwort. Als Nächstes folgen alle Switch-Arme in geschweiften Klammern. Der switch-Ausdruck nimmt weitere Verfeinerungen an der Syntax vor, die die switch-Anweisung umgibt. Das case-Schlüsselwort wird ausgelassen, und das Ergebnis jedes einzelnen Arms ist ein Ausdruck. Die letzten beiden Arme zeigen eine neue Sprachfunktion. Der { }-Fall entspricht jedem Objekt ungleich NULL, das nicht mit einem früheren Arm übereinstimmte. Dieser Arm fängt alle an diese Methode übergebenen inkorrekten Typen ab. Der { }-Fall muss den Fällen für jeden Fahrzeugtyp folgen. Wenn die Reihenfolge umgekehrt werden würde, hätte der { }-Fall Vorrang. Zum Schluss erkennt das null-Konstantenmuster, wenn null an diese Methode übergeben wird. Das null-Muster kann an letzter Stelle stehen, da die anderen Muster nur mit einem Nicht-NULL-Objekt des richtigen Typs übereinstimmen.
Sie können diesen Code mithilfe des folgenden Codes testen:Program.cs
using System;
using CommercialRegistration;
using ConsumerVehicleRegistration;
using LiveryRegistration;
using toll_calculator;
var tollCalc = new TollCalculator();
var car = new Car();
var taxi = new Taxi();
var bus = new Bus();
var truck = new DeliveryTruck();
Console.WriteLine($"The toll for a car is {tollCalc.CalculateToll(car)}");
Console.WriteLine($"The toll for a taxi is {tollCalc.CalculateToll(taxi)}");
Console.WriteLine($"The toll for a bus is {tollCalc.CalculateToll(bus)}");
Console.WriteLine($"The toll for a truck is {tollCalc.CalculateToll(truck)}");
try
{
tollCalc.CalculateToll("this will fail");
}
catch (ArgumentException e)
{
Console.WriteLine("Caught an argument exception when using the wrong type");
}
try
{
tollCalc.CalculateToll(null!);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Caught an argument exception when using null");
}
Dieser Code ist im Startprojekt enthalten, aber auskommentiert. Entfernen Sie die Kommentare, und Sie können testen, was Sie geschrieben haben.
Sie sehen jetzt, wie Muster Ihnen helfen können, Algorithmen zu erstellen, bei denen Code und Daten getrennt sind. Der switch-Ausdruck testet den Typ und produziert auf der Grundlage der Ergebnisse unterschiedliche Werte. Aber das ist nur der Anfang.
Belegungspreise hinzufügen
Die Mautbehörde möchte die Fahrzeuge dazu anregen, mit maximaler Kapazität zu fahren. Sie entscheiden sich, mehr zu berechnen, wenn Fahrzeuge weniger Passagiere haben und volle Fahrzeuge fördern, indem sie niedrigere Preise anbieten:
- PKWs und Taxis ohne Fahrgäste zahlen einen Aufschlag von 0,50 US-Dollar.
- PKWs und Taxis mit zwei Fahrgästen erhalten einen Rabatt von 0,50 US-Dollar.
- PKWs und Taxis mit mindestens drei Fahrgästen erhalten einen Rabatt von 1,00 US-Dollar.
- Busse, die zu weniger als 50% gefüllt sind, zahlen einen Aufschlag von 2,00 US-Dollar.
- Busse, die zu mehr als 90% ausgelastet sind, erhalten einen Rabatt von 1,00 US-Dollar.
Sie können diese Regeln implementieren, indem Sie ein Eigenschaftsmuster im gleichen Switchausdruck verwenden. Ein Eigenschaftsmuster vergleicht einen Eigenschaftswert mit einem konstanten Wert. Das Eigenschaftsmuster untersucht die Eigenschaften des Objekts, sobald der Typ bestimmt wurde.
Car {Passengers: 0} ist selbst ein rekursives Muster: Das äußere Eigenschaftenmuster Car enthält ein inneres Konstantenmuster, das den Passengers Wert testet. Der einzelne Fall eines Car wird auf vier verschiedene Fälle erweitert:
vehicle switch
{
Car {Passengers: 0} => 2.00m + 0.50m,
Car {Passengers: 1} => 2.0m,
Car {Passengers: 2} => 2.0m - 0.50m,
Car => 2.00m - 1.0m,
// ...
};
Die ersten drei Fällen testen den Typ als Car und überprüfen dann den Wert der Passengers-Eigenschaft. Wenn beide übereinstimmen, wird der Ausdruck ausgewertet und die Ausführung kehrt zurück.
Sie können auch die Anwendungsfälle für Taxis auf ähnliche Weise erweitern:
vehicle switch
{
// ...
Taxi {Fares: 0} => 3.50m + 1.00m,
Taxi {Fares: 1} => 3.50m,
Taxi {Fares: 2} => 3.50m - 0.50m,
Taxi => 3.50m - 1.00m,
// ...
};
Implementieren Sie als Nächstes die Belegungsregeln durch Erweitern der Fälle für Busse, wie im folgenden Beispiel gezeigt:
vehicle switch
{
// ...
Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
Bus => 5.00m,
// ...
};
Die Mautbehörde interessiert sich nicht für die Anzahl der Fahrgäste in Lieferwagen. Stattdessen passt sie die Mauthöhe basierend auf der Gewichtsklasse der Lieferwagen wie folgt an:
- Lkws über 2,3 Tonnen wird ein Aufschlag von 5,00 US-Dollar berechnet.
- Leichte Lieferwagen unter 1.363 kg (3.000 Pfund) erhalten einen Rabatt von 2,00 USD.
Sie können diese Regel mit dem folgenden Code implementieren:
vehicle switch
{
// ...
DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
DeliveryTruck => 10.00m,
};
Im vorherigen Code sehen Sie die when-Klausel eines switch-Arms. Verwenden Sie die when Klausel, um andere Bedingungen als Gleichheit für eine Eigenschaft zu testen. Wenn Sie fertig sind, haben Sie eine Methode, die ähnlich wie der folgende Code aussieht:
vehicle switch
{
Car {Passengers: 0} => 2.00m + 0.50m,
Car {Passengers: 1} => 2.0m,
Car {Passengers: 2} => 2.0m - 0.50m,
Car => 2.00m - 1.0m,
Taxi {Fares: 0} => 3.50m + 1.00m,
Taxi {Fares: 1} => 3.50m,
Taxi {Fares: 2} => 3.50m - 0.50m,
Taxi => 3.50m - 1.00m,
Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
Bus => 5.00m,
DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
DeliveryTruck => 10.00m,
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
Wie bereits erwähnt, sind diese switch-Arme rekursive Muster und verschachteln ein Konstantenmuster innerhalb eines Eigenschaftsmusters.
Sie können mit geschachtelten Switches die Wiederholungen in diesem Code reduzieren.
Car und Taxi weisen in den vorherigen Beispielen jeweils vier verschiedene Arme auf. In beiden Fällen können Sie ein Deklarationsmuster erstellen, das in ein konstantes Muster eingeht. Dieses Verfahren wird im folgenden Code dargestellt:
public decimal CalculateToll(object vehicle) =>
vehicle switch
{
Car c => c.Passengers switch
{
0 => 2.00m + 0.5m,
1 => 2.0m,
2 => 2.0m - 0.5m,
_ => 2.00m - 1.0m
},
Taxi t => t.Fares switch
{
0 => 3.50m + 1.00m,
1 => 3.50m,
2 => 3.50m - 0.50m,
_ => 3.50m - 1.00m
},
Bus b when ((double)b.Riders / (double)b.Capacity) < 0.50 => 5.00m + 2.00m,
Bus b when ((double)b.Riders / (double)b.Capacity) > 0.90 => 5.00m - 1.00m,
Bus b => 5.00m,
DeliveryTruck t when (t.GrossWeightClass > 5000) => 10.00m + 5.00m,
DeliveryTruck t when (t.GrossWeightClass < 3000) => 10.00m - 2.00m,
DeliveryTruck t => 10.00m,
{ } => throw new ArgumentException(message: "Not a known vehicle type", paramName: nameof(vehicle)),
null => throw new ArgumentNullException(nameof(vehicle))
};
Im vorherigen Beispiel bedeutet das Schachteln eines Schalterausdrucks in einem anderen Schalterarm, dass Sie die Car- und Taxi-Arme, die untergeordnete Arme enthalten, die den Eigenschaftswert testen, nicht wiederholen. Diese Technik wird nicht für die DeliveryTruck- und Bus-Arme verwendet, da diese Arme Bereiche für die Eigenschaft und keine diskreten Werte testen.
Spitzenpreisgestaltung hinzufügen
Für das letzte Feature möchte die Mautbehörde zeitabhängige Spitzenpreise hinzufügen. Während der morgendlichen und abendlichen Hauptverkehrszeiten werden die Mautgebühren verdoppelt. Diese Regel betrifft nur den Verkehr in einer Richtung: am Morgen den stadteinwärts und am Abend den stadtauswärts gehenden Verkehr. Während anderer Zeiten werden die Mautgebühren werktags um 50% heraufgesetzt. Am späten Abend und frühen Morgen werden die Mautgebühren um 25% verringert. Am Wochenende gelten unabhängig von der Zeit die normalen Gebühren. Sie können eine Reihe von if und else Anweisungen verwenden, um diese Regel mithilfe des folgenden Codes auszudrücken:
public decimal PeakTimePremiumIfElse(DateTime timeOfToll, bool inbound)
{
if ((timeOfToll.DayOfWeek == DayOfWeek.Saturday) ||
(timeOfToll.DayOfWeek == DayOfWeek.Sunday))
{
return 1.0m;
}
else
{
int hour = timeOfToll.Hour;
if (hour < 6)
{
return 0.75m;
}
else if (hour < 10)
{
if (inbound)
{
return 2.0m;
}
else
{
return 1.0m;
}
}
else if (hour < 16)
{
return 1.5m;
}
else if (hour < 20)
{
if (inbound)
{
return 1.0m;
}
else
{
return 2.0m;
}
}
else // Overnight
{
return 0.75m;
}
}
}
Der vorangehende Code funktioniert ordnungsgemäß, ist aber nicht lesbar. Sie müssen alle Eingabefälle und die geschachtelten if-Anweisungen durchlaufen, um den Code nachvollziehen zu können. Stattdessen verwenden Sie den Musterabgleich für dieses Feature, aber Sie integrieren es mit anderen Verfahren. Sie können einen einzelnen Mustervergleichsausdruck erstellen, der alle Kombinationen aus Richtung, Wochentag und Uhrzeit berücksichtigt. Das Ergebnis wäre ein komplizierter Ausdruck. Er wäre schwierig zu lesen und schwer zu verstehen. Dies erschwert, die Richtigkeit zu gewährleisten. Kombinieren Sie stattdessen diese Methoden, um ein Tupel von Werten zu erstellen, das alle diese Zustände präzise beschreibt. Berechnen Sie mithilfe des Musterabgleichs einen Multiplikator für die Maut. Das Tupel enthält drei diskrete Bedingungen:
- Der Tag ist entweder ein Wochentag oder fällt auf ein Wochenende.
- Der Zeitbereich, in dem die Maut erhoben wird.
- Die Richtung führt in die Stadt oder aus der Stadt heraus.
Die folgende Tabelle zeigt die Kombinationen von Eingabewerten und des Multiplikators für die Preisgestaltung für Spitzenzeiten:
| Tag | Zeit | Direction | Premium |
|---|---|---|---|
| Wochentag | morgendliche Hauptverkehrszeit | eingehend | x 2,00 |
| Wochentag | morgendliche Hauptverkehrszeit | ausgehend | x 1,00 |
| Wochentag | tagsüber | eingehend | x 1,50 |
| Wochentag | tagsüber | Ausgehend | x 1,50 |
| Wochentag | abendliche Hauptverkehrszeit | eingehend | x 1,00 |
| Wochentag | abendliche Hauptverkehrszeit | ausgehend | x 2,00 |
| Wochentag | nachts | eingehend | x 0,75 |
| Wochentag | nachts | ausgehend | x 0,75 |
| Wochenende | morgendliche Hauptverkehrszeit | eingehend | x 1,00 |
| Wochenende | morgendliche Hauptverkehrszeit | Ausgehend | x 1,00 |
| Wochenende | tagsüber | eingehend | x 1,00 |
| Wochenende | tagsüber | ausgehend | x 1,00 |
| Wochenende | abendliche Hauptverkehrszeit | eingehend | x 1,00 |
| Wochenende | abendliche Hauptverkehrszeit | ausgehend | x 1,00 |
| Wochenende | nachts | eingehend | x 1,00 |
| Wochenende | nachts | Ausgehend | x 1,00 |
Es gibt 16 verschiedene Kombinationen der drei Variablen. Indem Sie einige der Bedingungen kombinieren, vereinfachen Sie den endgültigen switch-Ausdruck.
Das System, das die Maut erhebt, verwendet eine DateTime-Struktur für die Uhrzeit, zu der die Maut erhoben wurde. Erstellen Sie Membermethoden, welche die Variablen aus der vorherigen Tabelle erzeugen. Die folgende Funktion verwendet einen Musterabgleichs-Switch-Ausdruck, um auszudrücken, ob ein DateTime ein Wochenende oder einen Wochentag darstellt.
private static bool IsWeekDay(DateTime timeOfToll) =>
timeOfToll.DayOfWeek switch
{
DayOfWeek.Monday => true,
DayOfWeek.Tuesday => true,
DayOfWeek.Wednesday => true,
DayOfWeek.Thursday => true,
DayOfWeek.Friday => true,
DayOfWeek.Saturday => false,
DayOfWeek.Sunday => false
};
Diese Methode ist korrekt, sie ist jedoch repetitiv. Sie können sie vereinfachen, wie im folgenden Code gezeigt:
private static bool IsWeekDay(DateTime timeOfToll) =>
timeOfToll.DayOfWeek switch
{
DayOfWeek.Saturday => false,
DayOfWeek.Sunday => false,
_ => true
};
Fügen Sie als Nächstes eine ähnliche Funktion hinzu, um die Zeit in den Blöcken zu kategorisieren:
private enum TimeBand
{
MorningRush,
Daytime,
EveningRush,
Overnight
}
private static TimeBand GetTimeBand(DateTime timeOfToll) =>
timeOfToll.Hour switch
{
< 6 or > 19 => TimeBand.Overnight,
< 10 => TimeBand.MorningRush,
< 16 => TimeBand.Daytime,
_ => TimeBand.EveningRush,
};
Sie fügen eine private enum-Klasse hinzu, um jeden Zeitbereich in einen diskreten Wert zu konvertieren. Anschließend verwendet die GetTimeBand Methode relationale Muster und logische Muster. Ein relationales Muster ermöglicht es Ihnen, einen numerischen Wert mithilfe von <, >, <= oder >= zu testen. Logische Muster kombinieren andere Muster: Ein or Muster testet, ob ein Ausdruck mit einem oder mehreren Mustern übereinstimmt, ein and Muster testet, dass ein Ausdruck mit zwei verschiedenen Mustern übereinstimmt, und ein not Muster testet, dass ein Ausdruck nicht mit einem Muster übereinstimmt.
Nachdem Sie diese Methoden erstellt haben, können Sie einen anderen switch Ausdruck mit einem Tupelmuster – einem Positionsmuster , das jedem Element eines Tupels entspricht – verwenden, um die Preisprämie zu berechnen. Sie könnten einen switch-Ausdruck mit allen 16 Armen erstellen:
public decimal PeakTimePremiumFull(DateTime timeOfToll, bool inbound) =>
(IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
{
(true, TimeBand.MorningRush, true) => 2.00m,
(true, TimeBand.MorningRush, false) => 1.00m,
(true, TimeBand.Daytime, true) => 1.50m,
(true, TimeBand.Daytime, false) => 1.50m,
(true, TimeBand.EveningRush, true) => 1.00m,
(true, TimeBand.EveningRush, false) => 2.00m,
(true, TimeBand.Overnight, true) => 0.75m,
(true, TimeBand.Overnight, false) => 0.75m,
(false, TimeBand.MorningRush, true) => 1.00m,
(false, TimeBand.MorningRush, false) => 1.00m,
(false, TimeBand.Daytime, true) => 1.00m,
(false, TimeBand.Daytime, false) => 1.00m,
(false, TimeBand.EveningRush, true) => 1.00m,
(false, TimeBand.EveningRush, false) => 1.00m,
(false, TimeBand.Overnight, true) => 1.00m,
(false, TimeBand.Overnight, false) => 1.00m,
};
Der vorangehende Code funktioniert, kann aber vereinfacht werden. Alle acht Kombinationen für das Wochenende haben die gleiche Gebühr. Sie können alle acht mit der folgenden Zeile ersetzen:
(false, _, _) => 1.0m,
Sowohl stadteinwärts als auch stadtauswärts gehender Verkehr haben an Wochentagen tagsüber und nachts den gleichen Multiplikator. Sie können diese vier Schalterarme durch die folgenden beiden Zeilen ersetzen:
(true, TimeBand.Overnight, _) => 0.75m,
(true, TimeBand.Daytime, _) => 1.5m,
Der Code sollte nach diesen beiden Änderungen folgendermaßen aussehen:
public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
(IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
{
(true, TimeBand.MorningRush, true) => 2.00m,
(true, TimeBand.MorningRush, false) => 1.00m,
(true, TimeBand.Daytime, _) => 1.50m,
(true, TimeBand.EveningRush, true) => 1.00m,
(true, TimeBand.EveningRush, false) => 2.00m,
(true, TimeBand.Overnight, _) => 0.75m,
(false, _, _) => 1.00m,
};
Entfernen Sie schließlich die zwei Stoßzeiten, für die der reguläre Preis gilt. Nachdem Sie diese Arme entfernt haben, ersetzen Sie das false durch ein Verwerfen (_) im letzten Schalterarm. Sie erhalten die folgende fertige Methode:
public decimal PeakTimePremium(DateTime timeOfToll, bool inbound) =>
(IsWeekDay(timeOfToll), GetTimeBand(timeOfToll), inbound) switch
{
(true, TimeBand.Overnight, _) => 0.75m,
(true, TimeBand.Daytime, _) => 1.5m,
(true, TimeBand.MorningRush, true) => 2.0m,
(true, TimeBand.EveningRush, false) => 2.0m,
_ => 1.0m,
};
Dieses Beispiel verdeutlicht einen der Vorteile von Musterabgleich: Die Musterverzweigungen werden der Reihe nach ausgewertet. Wenn Sie sie neu anordnen, sodass eine frühere Verzweigung einen Ihrer späteren Fälle verarbeitet, gibt der Compiler einen Warnhinweis zum unerreichbaren Code aus. Diese Sprachregeln haben die Durchführung der vorherigen Vereinfachungen erleichtert mit der Zuversicht, dass der Code sich nicht geändert hat.
Ein Musterabgleich führt dazu, dass einige Codetypen leichter lesbar sind, und bietet eine Alternative zu objektorientierten Verfahren, wenn Ihren Klassen kein Code hinzugefügt werden kann. Die Cloud sorgt dafür, dass Daten und Funktionen getrennt bleiben. Die Form der Daten und die daran ausgeführten Vorgänge werden nicht notwendigerweise zusammen beschrieben. In diesem Tutorial haben Sie vorhandene Daten auf von ihrer ursprünglichen Funktion völlig unterschiedliche Arten verwendet. Der Musterabgleich ermöglichte Ihnen, Funktionalität zu schreiben, die diese Typen überschreibt, auch wenn Sie sie nicht erweitern konnten.
Nächste Schritte
Sie können den fertig gestellten Code aus dem Repository dotnet/samples auf GitHub herunterladen. Untersuchen Sie Muster auf eigene Faust, und nehmen Sie dieses Verfahren in Ihre Codierungsgewohnheiten auf. Wenn Sie diese Verfahren lernen, eröffnet sich Ihnen ein anderer Weg, Probleme anzugehen und neue Funktionalität zu erstellen.