Ab C # 8.0 unter .NET Core 3.0 können Sie beim Erstellen eines Mitglieds einer Schnittstelle deren Implementierung bestimmen. Das häufigste Szenario ist das sichere Hinzufügen von Mitgliedern zu einer Schnittstelle, die bereits von unzähligen Clients freigegeben und verwendet wird.
In diesem Handbuch erfahren Sie, wie Sie:
- Es ist sicher, Schnittstellen durch Hinzufügen von Methoden mit Implementierungen zu erweitern.
- Erstellen Sie parametrisierte Implementierungen für mehr Flexibilität.
- Erhalten Sie das Recht, spezifischere Implementierungen mit der Möglichkeit der manuellen Steuerung zu implementieren.

Wo soll ich anfangen?
Zuerst müssen Sie den Computer für die Verwendung mit .NET Core konfigurieren, einschließlich des Compilers aus der C # 8.0-Vorschau. Ein solcher Compiler ist ab Visual Studio 2019 oder mit dem neueren .NET Core 3.0 Preview SDK verfügbar. Standardschnittstellenmitglieder sind ab .NET Core 3.0 (Vorschau 4) verfügbar.
Szenarioübersicht
Dieses Tutorial beginnt mit der ersten Version der Kundenbeziehungsbibliothek. Sie können die Starter-App in unserem Repository auf GitHub herunterladen . Das Unternehmen, das diese Bibliothek erstellt hat, ging davon aus, dass Kunden mit vorhandenen Anwendungen sie an diese Bibliothek anpassen würden. Den Benutzern wurden die Mindestschnittstellendefinitionen für die Implementierung vorgestellt:
public interface ICustomer { IEnumerable<IOrder> PreviousOrders { get; } DateTime DateJoined { get; } DateTime? LastOrder { get; } string Name { get; } IDictionary<DateTime, string> Reminders { get; } }
Es wurde auch eine zweite Schnittstelle definiert, die die Reihenfolge anzeigt:
public interface IOrder { DateTime Purchased { get; } decimal Cost { get; } }
Basierend auf diesen Schnittstellen kann das Team eine Bibliothek für seine Benutzer erstellen, um die beste Erfahrung für Kunden zu schaffen. Ziel des Teams war es, die Interaktion mit bestehenden Kunden zu verbessern und Beziehungen zu neuen Kunden aufzubauen.
Es ist Zeit, die Bibliothek für die nächste Version zu aktualisieren. Eine der beliebtesten Funktionen ist die Hinzufügung von Rabatten für treue Kunden, die eine große Anzahl von Bestellungen aufgeben. Dieser neue individuelle Rabatt wird jedes Mal angewendet, wenn ein Kunde eine Bestellung aufgibt. Mit jeder Implementierung von ICustomer können unterschiedliche Regeln für einen Rabatt für die Loyalität festgelegt werden.
Der bequemste Weg, diese Funktion hinzuzufügen, besteht darin, die ICustomer
Oberfläche mit Rabatten zu erweitern. Dieser Vorschlag hat bei erfahrenen Entwicklern Besorgnis ausgelöst. „Schnittstellen sind nach der Veröffentlichung unveränderlich! Dies ist eine kritische Änderung! “ In C # 8.0 wurden Standardschnittstellenimplementierungen zum Aktualisieren von Schnittstellen hinzugefügt. Bibliotheksautoren können neue Mitglieder hinzufügen und standardmäßig implementieren
Die Standardimplementierung von Schnittstellen ermöglicht es Entwicklern, die Schnittstelle zu aktualisieren, während andere Entwickler diese Implementierung überschreiben können. Bibliotheksbenutzer können die Standardimplementierung als unkritische Änderung akzeptieren.
Aktualisieren Sie mit Standardschnittstellenmitgliedern
Das Team stimmte der wahrscheinlichsten Standardimplementierung zu: einem Rabatt auf die Kundenbindung.
Das Update muss funktionsfähig sein, um zwei Eigenschaften festzulegen: die Anzahl der Bestellungen, die erforderlich sind, um einen Rabatt zu erhalten, und den Prozentsatz des Rabatts. Dies macht es zu einem idealen Skript für Standardschnittstellenmitglieder. Sie können der ICustomer-Schnittstelle eine Methode hinzufügen und deren wahrscheinlichste Implementierung bereitstellen. Alle vorhandenen und alle neuen Implementierungen können standardmäßig implementiert werden oder haben ihre eigenen Einstellungen.
Fügen Sie der Implementierung zunächst eine neue Methode hinzu:
Der Autor der Bibliothek hat den ersten Test geschrieben, um die Implementierung zu überprüfen:
SampleCustomer c = new SampleCustomer("customer one", new DateTime(2010, 5, 31)) { Reminders = { { new DateTime(2010, 08, 12), "childs's birthday" }, { new DateTime(1012, 11, 15), "anniversary" } } }; SampleOrder o = new SampleOrder(new DateTime(2012, 6, 1), 5m); c.AddOrder(o); o = new SampleOrder(new DateTime(2103, 7, 4), 25m); c.AddOrder(o);
Beachten Sie den folgenden Teil des Tests:
Dieser Teil, von SampleCustomer
bis ICustomer
ist wichtig. Die SampleCustomer
Klasse SampleCustomer
keine Implementierung für ComputeLoyaltyDiscount
. Dies wird von der ICustomer
Oberfläche ICustomer
. Die SampleCustomer
Klasse erbt SampleCustomer
keine Mitglieder von ihren Schnittstellen. Diese Regel hat sich nicht geändert. Um eine in einer Schnittstelle implementierte Methode aufzurufen, muss die Variable ein Schnittstellentyp sein, in diesem Beispiel ICustomer
.
Parametrierung
Dies ist ein guter Anfang. Die Standardimplementierung ist jedoch zu begrenzt. Viele Verbraucher dieses Systems können unterschiedliche Schwellenwerte für die Anzahl der Käufe, unterschiedliche Mitgliedschaftsdauern oder unterschiedliche Rabatte in Prozent auswählen. Sie können den Upgrade-Prozess für mehr Kunden verbessern, indem Sie diese Parameter festlegen. Fügen wir eine statische Methode hinzu, die diese drei Parameter festlegt, die die Standardimplementierung steuern:
Dieser kleine Code zeigt viele neue Sprachfunktionen. Schnittstellen können jetzt statische Elemente enthalten, einschließlich Felder und Methoden. Verschiedene Zugriffsmodifikatoren sind ebenfalls enthalten. Zusätzliche Felder sind privat und die neue Methode ist öffentlich. Alle Modifikatoren sind für Schnittstellenmitglieder zulässig.
Anwendungen, die die allgemeine Formel zur Berechnung von Treuerabatten verwenden, jedoch unterschiedliche Parameter aufweisen, sollten keine benutzerdefinierte Implementierung bereitstellen. Sie können Argumente mit der statischen Methode festlegen. Der folgende Code legt beispielsweise die „Kundenbewertung“ fest, mit der jeder Kunde mit einer Mitgliedschaft von mehr als einem Monat belohnt wird:
ICustomer.SetLoyaltyThresholds(new TimeSpan(30, 0, 0, 0), 1, 0.25m); Console.WriteLine($"Current discount: {theCustomer.ComputeLoyaltyDiscount()}");
Erweitern Sie die Standardimplementierung
Der zuvor hinzugefügte Code bot eine praktische Implementierung für jene Szenarien, in denen Benutzer so etwas wie die Standardimplementierung oder einen nicht verwandten Satz von Regeln bereitstellen möchten. Lassen Sie uns für die endgültige Version den Code ein wenig neu organisieren, um Szenarien einzuschließen, in denen Benutzer sich möglicherweise auf die Standardimplementierung verlassen möchten.
Stellen Sie sich ein Startup vor, das neue Kunden gewinnen möchte. Sie bieten einen Rabatt von 50% auf die erste Bestellung eines neuen Kunden. Bestehende Kunden erhalten einen Standardrabatt. Der Autor der Bibliothek muss die Standardimplementierung in die protected static
Methode verschieben, damit jede Klasse, die diese Schnittstelle implementiert, den Code in ihrer Implementierung wiederverwenden kann. Die Standardimplementierung eines Schnittstellenmitglieds ruft auch diese generische Methode auf:
public decimal ComputeLoyaltyDiscount() => DefaultLoyaltyDiscount(this); protected static decimal DefaultLoyaltyDiscount(ICustomer c) { DateTime start = DateTime.Now - length; if ((c.DateJoined < start) && (c.PreviousOrders.Count() > orderCount)) { return discountPercent; } return 0; }
In der Implementierung der Klasse, die diese Schnittstelle implementiert, können Sie die statische Hilfsmethode manuell aufrufen und diese Logik erweitern, um dem „neuen Client“ einen Rabatt zu gewähren:
public decimal ComputeLoyaltyDiscount() { if (PreviousOrders.Any() == false) return 0.50m; else return ICustomer.DefaultLoyaltyDiscount(this); }
Sie können den gesamten fertigen Code in unserem Repository auf GitHub sehen .
Durch diese neuen Funktionen können Schnittstellen sicher aktualisiert werden, wenn für neue Mitglieder eine akzeptable Standardimplementierung vorliegt. Entwerfen Sie Schnittstellen sorgfältig, um individuelle funktionale Ideen auszudrücken, die von mehreren Klassen umgesetzt werden können. Dies erleichtert das Aktualisieren dieser Schnittstellendefinitionen, wenn neue Anforderungen für dieselbe Funktionsidee gefunden werden.