Back To Top

Erstellung von Schnittstellen (interfaces) in C#.NET

Schnittstellen in C#.NET

Comelio-Blog C#.NET SchnittstellenEine Schnittstelle wird gemeinhin als Vertrag bezeichnet, der durch die Überwachung des Compilers sicherstellt, auch eingehalten zu werden. Dies führt dazu, dass die in einer Schnittstelle deklarierten Komponenten tatsächlich in den die Schnittstelle implementierenden Klassen vorhanden sind.

Grundlagen

Comelio-Blog C#.NET SchnittstellenDie Funktions- und Verwendungsweise ähnelt sehr der Vererbung über Klassen, wobei jedoch von der Schnittstelle selbst kein Objekt instanziierbar ist, sondern nur Implementierungsvorschriften, aber keine Implementierungen vorhanden sind.

Die allgemeine Syntax hat folgenden Aufbau:

[attributes] [modifiers] interface identifier [:base-list] {interface-body}[;]

Die einzelnen Bestandteile beinhalten:

  • Die Attribute bieten zusätzliche deklarative Informationen.
  • Die Modifizierer sind entweder die Zugriffsmodifizierer oder das Schlüsselwort new.
  • Das Schlüsselwort interface selbst.
  • Der Name desselben.
  • Die Basisliste kann kommagetrennte Reihe von anderen Schnittstellen enthalten, welche das aktuelle Interface implementieren soll.
  • Innerhalb von geschweiften Klammern stehen die Inhalte der Schnittstelle.

Als Inhalte kommen Methoden, Eigenschaften, Indexer und Ereignisse in Betracht. Sie werden als reine Rümpfe angekündigt und müssen dann implementiert werden. Dies führt dazu, dass man sich bei Klassen, welche die Schnittstelle implementieren, darauf verlassen kann, die entsprechenden Konstrukte dort wieder zu finden.

Im Gegensatz zur Vererbung ist es bei der Schnittstellenimplementierung möglich, mehrere Schnittstellen zu implementieren, welche in einer kommagetrennten Liste aufgezählt werden.

Ein Interface kann andere Schnittstellen implementieren, die als Liste nach einem Doppelpunkt, der dem Namen folgt, aufgezählt werden. Als Name hat sich in C# eingebürgert, ein I als Präfix zu verwenden, damit man die Schnittstellen leicht von Klassen unterscheiden kann und Schwierigkeiten, immer neue Bezeichner für ähnliche Sachverhalte (Oberbegriff von Person oder Fahrzeug?) zu finden, vermeidet.

interface ISchnittstelle: I1, I2 {
   void MethodeA();
   void MethodeB();
}

Eine Klasse ermöglicht dann die Implementierung, indem ebenfalls nach einem Doppelpunkt, der dem Namen folgt, die einzelnen Schnittstellen aufgerufen werden.

class Klasse1: I1, I2 {
   // ausprogrammierte Methoden, Eigenschaften, Indexer, Ereignisse
}

Es ist gleichzeitig möglich, eine Vererbungshierarchie zu erstellen und Schnittstellen zu implementieren, wobei die Basisklasse als erste Nennung in der Aufzählung erscheint. Da nur einfache Vererbung zulässig ist, genügt hier eine Anordnung über die Position.

class KlasseB: BasisKlasse, I1, I2 {
  // ausprogrammierte Methoden, Eigenschaften, Indexer, Ereignisse
}

Sinn und Zweck einer Schnittstelle ist es, die öffentlichen Mitglieder einer Klasse bekannt zu machen. Es ist bei der Ankündigung dieser Mitglieder kein Zugriffsmodifizierer zulässig, da alle aufgelisteten Mitglieder öffentlich sind.

Durch die Implementierung und Bereitstellung einer solchen Schnittstelle herrscht also einerseits Klarheit über die öffentlichen Mitglieder und damit die Außenansicht von Objekten, während andererseits von der Schnittstelle kein Objekt erzeugt werden darf. Diesen Wunsch hat man normalerweise sehr schnell, weil bei der einfachen Vererbung wie in den zurückliegenden Beispielen zuvor, stets auch die Möglichkeit bestand, ein Objekt vom Typ Koerper oder Produkt zu erzeugen, welches allerdings in der Software nicht gewünscht wurde, weil es keinen nutzbaren Wert hatte. Irgendein Produkt oder irgendeinen Körper kann man nicht verwenden. Ein Buch, eine CD oder ein Rechteck bzw. ein Quader dagegen durchaus. In diesen Fällen kann man die Instanziierung der Oberstruktur durch eine Schnittstelle oder eine abstrakte Klasse verhindern und legt daher nur die Außensicht möglicher konkreter Objekte fest.

Die Implementierung bietet die gleichen Fähigkeiten wie beim dynamischen Binden durch Vererbung. Man kann, wie im nächsten Beispiel gezeigt wird, einen Schnittstellentyp verarbeiten, welcher zur Laufzeit immer von einem passenden Untertyp ausgefüllt wird. Durch die Klammerung, die mit Hilfe der Schnittstelle ausgeübt wird, führt die Verarbeitung immer zu vorhandenen öffentlichen Mitgliedern.

Syntaxbeispiel

Comelio-Blog C#.NET SchnittstellenIn einem Beispiel soll die grundsätzliche Syntax dargestellt werden. Dabei greifen wir noch einmal auf das bereits bekannte Beispiel mit geometrischen Körpern zurück. Es ermöglicht Ihnen, einen Blick zu der Vererbung mit Hilfe von Klassen zu werfen, die Syntax und die Funktionsweise zu vergleichen. Sogar die Vorteile durch die Schnittstellenverwendung lassen sich nachvollziehen, denn ein einfacher Koerper ist für diese sehr kleine Software tatsächlich so nutzlos, dass wir die Vorteile, die durch die Vererbung entstehen, mit Hilfe einer Schnittstelle gleichfalls erhalten und darüber hinaus auch noch das Erzeugen von nutzlosen Körper verbieten.

Zunächst erstellt man eine Schnittstelle, die im Gegensatz zur Klasse Koerper nun IKoeper heißt. Da keine Felder angegeben werden können, sind Eigenschaften erforderlich. Diese sollten nur lesbar sein, weil die Werte über den Konstruktor in die Klasse geraten, weswegen nur get-Umsetzungen gefordert werden und auf set verzichtet wird.

public interface IKoerper {
   // Eigenschaften
   int laenge { get; }
   int breite { get; }
   int hoehe  { get; }
   // Methoden
   double errechneFlaeche();
}

Erstellung einer Schnittstelle

Von den drei zu erstellenden Einzelklassen zeigen wir nur die für Quadrat. Die anderen sind entsprechend ähnlich aufgebaut, wie auch noch die gleich folgende UML-Zeichnung zeigen wird. Hier werden die einzelnen geforderten Mitglieder ausprogramiert und sinnvoll mit Leben gefüllt. Die Angabe, dass eine Schnittstelle implementiert wird, erfolgt syntaktisch genauso wie bei der Ableitung, sodass nur am vorgesetzten Buchstaben I zu erkennen, dass es sich hierbei um eine Implementierung handelt.

public class Quadrat : IKoerper {  
   // Felder
   private int _laenge;
   // Eigenschaften
   public int laenge {
      get { return _laenge; }
   }
    public int hoehe {
        get { return 0; }
    }
    public int breite {
        get { return _laenge; }
    }
   // Methoden
   public Quadrat(int laenge) {
      _laenge = laenge;
   }
   public double errechneFlaeche() {
            return laenge * laenge;
        }
}

Verwendung einer Schnittstelle bei der Erzeugung einer Klasse

Als Klientenquelltext dient eine FormFabrik zur zufälligen Erzeugung von geometrischen Formen. Interessant ist, dass als Rückgabedatentyp der Schnittstellennamen steht. Obwohl kein Objekt zu bilden ist, ist der Typname für die Datentypen von Rückgabe- und Übergabeparametern zu verwenden. Dies ist ein entsprechend wichtiger Punkt für den Klassenaufbau und den Nutzen, der durch Schnittstellen entsteht.

public class FormFabrik  {
  // Erzeugung von Formen
  public IKoerper erzeugeForm() {
     Random zufall = new Random();
     double zahl = Math.Round(zufall.NextDouble() * 10, 0);
     if (zahl < 5) { return new Rechteck(3, 4); }
     else { return new Quader(3, 4, 5); }
  }
}

Rückgabe eines Schnittstellen-Types

Ganz zum Schluss nun erfolgt in der Page_Load-Methode nun zum einen die traditionelle Erzeugung eines Objekts über statische Bindung, in der einfach der Objektname eingetragen wird. Zum anderen setzt man die KnotenFabrik ein, welche ein nicht näher spezifizierbares IKoerper-Objekt zurückliefert. Obschon wir nicht wissen, von welchem Typ es ist, lässt sich seine passende errechneFlaeche-Methode ausgeben. Sollte Ihnen also die dynamische Bindung bereits als nützliches Werkzeug erscheinen, dann ist die Ausgabe von 12 oder 94 der Beweis für die Funktionstüchtigkeit derselben mit Hilfe einer Schnittstelle. An dieser Stelle kann man sich also darauf verlassen, was Sinn und Zweck des so genannten Vertrages zwischen Klasse und Schnittstelle ist, dass die durch die Schnittstelle als öffentlich deklarierten Mitglieder bei jedem implementierenden Objekt auch tatsächlich einsetzbar sind.

// Objekte erzeugen
Quadrat quadrat = new Quadrat(3);
ausgabe.Text += quadrat.errechneFlaeche() + "
"; // Objekte zufällig erzeugen FormFabrik fabrik = new FormFabrik(); IKoerper form = fabrik.erzeugeForm(); // Quader = 94, Rechteck = 12 ausgabe.Text += form.errechneFlaeche();

Verwendung

Der Vollständigkeit und Übersicht halber folgt das UML-Diagramm, in dem auch die hier aus Platzgründen nicht abgedruckten Klassen für Rechteck und Quadrat erscheinen. Eine Schnittstelle lässt sich durch die kursive Schreibweise von zu implementierenden Mitgliedern und das zusätzliche Stereotyp <<interfacce>> erkennen. Die Implementierung durch die drei Form-Klassen erfolgt dann symbolisch durch einen gestrichelten Pfeil mit einer nicht ausgefüllten Spitze. Ansonsten lassen sich genauso wie bei einer Elternklasse auch Assoziationen von anderen Klassen mit dieser Schnittstelle verbinden, was in unserem Fall für die FormFabrik der Fall ist.

Schnittstelle

Schnittstelle

» Kontaktformular










comelio.com

mail address

mail address

  • Berlin | Comelio GmbH
    Fon: +49(0)30-8145622-00
    Fax: +49(0)30-8145622-10
  • München | Comelio GmbH
    Fon: +49(0)89-38156860-0
    Fax: +49(0)89-38156860-9
  • Hamburg | Comelio GmbH
    Fon: +49(0)40-20934996-0
    Fax: +49(0)40-20934996-9
  • Wien | Comelio GmbH
    Fon: +43-720-2097-97
    Fax: +43-720-2097-98