Explizite Interfaces
Teil des Abschnitts Objektorientierte Programmierung der C#-Journey von Coddy. Lektion 28 von 70.
Wenn eine Klasse mehrere Schnittstellen implementiert, die Member mit demselben Namen haben, tritt ein Namenskonflikt auf. Die explizite Schnittstellenimplementierung löst dies, indem sie es Ihnen ermöglicht, separate Implementierungen für jede Schnittstelle bereitzustellen.
Bei der expliziten Implementierung stellen Sie dem Membernamen den Schnittstellennamen voran und lassen den Zugriffsmodifizierer weg:
public interface IAmericanPlug
{
void Connect();
}
public interface IEuropeanPlug
{
void Connect();
}
public class UniversalAdapter : IAmericanPlug, IEuropeanPlug
{
void IAmericanPlug.Connect()
{
Console.WriteLine("Connected to 120V");
}
void IEuropeanPlug.Connect()
{
Console.WriteLine("Connected to 220V");
}
}Explizit implementierte Member können nur über eine Variable des Schnittstellentyps aufgerufen werden, nicht über die Klasse selbst:
var adapter = new UniversalAdapter();
// adapter.Connect(); // Kompiliert nicht!
IAmericanPlug american = adapter;
american.Connect(); // Verbunden mit 120V
IEuropeanPlug european = adapter;
european.Connect(); // Verbunden mit 220VDiese Technik ist auch nützlich, wenn du Schnittstellenmitglieder vor der öffentlichen API der Klasse verbergen möchtest. Wenn eine Methode nur sinnvoll ist, wenn das Objekt als eine bestimmte Schnittstelle behandelt wird, hält die explizite Implementierung die Oberfläche deiner Klasse sauber und erfüllt dennoch den Vertrag.
Aufgabe
EinfachErstellen wir ein Berichtsgeneratorsystem, das veranschaulicht, wie die explizite Implementierung von Schnittstellen es einer einzelnen Klasse ermöglicht, je nach verwendeter Schnittstelle unterschiedliches Verhalten bereitzustellen. Du erstellst ein Dokument, das für die Anzeige anders formatiert werden kann als für den Druck.
Du organisierst deinen Code auf vier Dateien verteilt:
IDisplayable.cs: Definiere im NamespaceIDisplayableeine Schnittstelle namensReports. Diese Schnittstelle steht für Inhalte, die auf dem Bildschirm angezeigt werden können. Sie soll eine MethodeRender()deklarieren, die einen String zurückgibt.IPrintable.cs: Definiere im NamespaceIPrintableeine Schnittstelle namensReports. Diese Schnittstelle steht für Inhalte, die an einen Drucker gesendet werden können. Sie soll ebenfalls eine MethodeRender()deklarieren, die einen String zurückgibt – beachte, dass dadurch ein Namenskonflikt mitIDisplayableentsteht!Report.cs: Definiere im NamespaceReporteine KlasseReports, die sowohlIDisplayableals auchIPrintableimplementiert. Der Bericht soll über eineTitle-Eigenschaft (string) und eineContent-Eigenschaft (string) verfügen, wobei ein Konstruktor beide Werte festlegt. Verwende die explizite Implementierung von Schnittstellen, um unterschiedliches Verhalten fürRender()bereitzustellen:- Bei der Anzeige:
"[SCREEN] {Title}: {Content}" - Beim Drucken:
"[PRINT] {Title} | {Content}"
- Bei der Anzeige:
Program.cs: Erstelle in deiner Hauptdatei mithilfe von Eingabewerten einReport-Objekt. Da explizite Implementierungen nur über Schnittstellenvariablen aufgerufen werden können, speicherst du denselben Bericht sowohl in einerIDisplayable-Variable als auch in einerIPrintable-Variable und rufst anschließend für beideRender()auf, um zu zeigen, wie dasselbe Objekt je nach verwendeter Schnittstelle eine unterschiedliche Ausgabe erzeugt.
Du erhältst zwei Eingaben:
- Berichtstitel
- Berichtsinhalt
Gib die Ausgabe in diesem Format aus:
Display version:
{Render() via IDisplayable}
Print version:
{Render() via IPrintable}Wenn die Eingaben beispielsweise Sales Report und Q4 revenue increased by 15% lauten, sollte die Ausgabe wie folgt aussehen:
Display version:
[SCREEN] Sales Report: Q4 revenue increased by 15%
Print version:
[PRINT] Sales Report | Q4 revenue increased by 15%Beachte, wie sich dasselbe Report-Objekt je nach verwendeter Schnittstellenreferenz unterschiedlich verhält. Das ist die Stärke der expliziten Implementierung von Schnittstellen – sie löst Namenskonflikte und ermöglicht gleichzeitig kontextgerechtes Verhalten!
Probier es selbst
using System;
using Reports;
class Program
{
public static void Main(string[] args)
{
// Eingabe lesen
string title = Console.ReadLine();
string content = Console.ReadLine();
// TODO: Erstelle ein Report-Objekt mit dem Titel und Inhalt
// TODO: Speichere den Bericht in einer IDisplayable-Variable
// TODO: Speichere denselben Bericht in einer IPrintable-Variable
// TODO: Gib die Anzeigeversion aus, indem Render() auf IDisplayable aufgerufen wird
Console.WriteLine("Display version:");
// Gib das Render-Ergebnis hier aus
// TODO: Gib die Druckversion aus, indem Render() auf IPrintable aufgerufen wird
Console.WriteLine("Print version:");
// Gib das Render-Ergebnis hier aus
}
}
Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.
Alle Lektionen in Objektorientierte Programmierung
1Grundlagen der OOP
Externe DateienNamespaces & DirektivenEinführung in Klassen & ObjekteDas 'this'-SchlüsselwortMethoden und ParameterFelder vs. EigenschaftenKonstruktorenObjektinitialisiererWiederholung – Einfacher Taschenrechner4Vererbung
Grundlegende Vererbungs-(:)-SyntaxDas „base“-Schlüsselwort„virtual“- und „override“-SchlüsselwörterVersiegelte KlassenDie „object“-BasisklasseWiederholung – Mitarbeiterhierarchie7Erweiterte Funktionen
Überladen von OperatorenIndexer (this[])ToString()-ÜberschreibungErweiterungsmethodenRückblick – Benutzerdefinierte Liste10Entwurfsmuster Teil 1
Einführung in EntwurfsmusterThread-sicheres SingletonFactory-MusterObserver-Muster (Events)Strategy-Muster13Abschließende Herausforderungen
E-Learning-PlattformKomponente für SpielfigurenFahrzeugvermietungsdienst2Eigenschaften & statische Member
Automatisch implementierte EigenschaftenNur lesbare/schreibbare EigenschaftenStatische Felder & MethodenStatische KlassenMember mit Ausdruckskörpern5Polymorphie & Interfaces
Compile- vs. Laufzeit-PolymorphieInterface vs. abstrakte KlasseMehrere InterfacesExplizite InterfacesUpcasting & DowncastingWiederholung – Formenrechner3Klassenarchitektur
Instanz- vs. statische DatenSchlüsselwörter 'readonly' & 'const'Backing FieldsRückblick – Bankkontenverwaltung6Kapselung
ZugriffsmodifikatorenEigenschaften zur KapselungImplementierung der DatenkapselungMuster für UnveränderlichkeitRückblick – SchülerdatenÜbe selbstständig: Online-C#-Compiler