Interfaces in C#
Monday, May 2nd, 2011Hallo,
kürzlich habe ich zur Auffrischung meines C#-Wissens die neue Auflage von “Effective C#“ bestellt und begonnen, die einzelnen Items durchzuschauen. Das Item 23 “Understand How Interfaces differ from Virtual Methods” hat mich dann doch einigermaßen beeindruckt, gibt es doch einen Eindruck von der Fülle an Konzepten die zum Thema “Interfaces” in C# relevant sind. Beim Versuch eine Webpage oder Blog-posting zu finden, in dem ein mehr oder weniger vollständiger Überblick über dieses Thema gegeben wird, habe ich aber nichts brauchbares gefunden. Die meisten Fundstellen waren Einführungen in das Thema Interfaces im allgemeinen und begnügten sich damit, das Konzept vorzustellen und zu motivieren.
In diesem Posting versuche ich einen eher Referenz-artigen aber hoffentlich vollständigen Überblick über die Eigenheiten und Möglichkeiten von Interfaces in C# zu geben. Das Konzept an sich und die übliche Verwendung werde ich nicht weiter Erläutern.
Methoden in Interfaces sind per default nicht virtuell
Per default sind Methoden in Interfaces nicht virtuell. D.h. wenn eine Objektreferenz den Typ des Interfaces hat, wird immer die Methode der obersten Klasse in der Vererbungshierarchie gerufen, die die Methode implementiert. Die erneute Implementierung einer Interfaces-Methode in einer abgeleiteten Klasse ist überhaupt nur unter Verwendung des Schlüsselwortes new möglich, was bereits auf das beschriebene Verhalten hinweist.
Interfaces können in verschiedenen Ebenen der Vererbungshierarchie implementiert werden
Wenn man von einer vorhandenen Klasse ableitet und mit deren Implementierung eines Interfaces nicht zufrieden ist, besteht die Möglichkeit, das Interface in der abgeleiteten Klasse erneut zu implementieren. Dazu erklärt man auch in der abgeleiteten Klasse, dass man das Interface definiert. In diesem Fall wird bei Verwendung einer Objektreferenz vom Typ des Interfaces die “tiefstmögliche” (bezogen auf die Vererbungshierarchie) Implementierung gerufen.
Dieses Vorgehen ist aber auch nicht ganz unproblematisch:
- Die Verwendung des Schlüsselwortes new ist immer noch nötig
- Es müssen alle Methoden des Interfaces implementiert werden, auch wenn man nur eine Teilmenge ersetzen will
- Wenn man eine Referenz mit dem Typ einer direkten oder indirekten Superklasse zum Aufruf einer Methode verwendet, die Teil des Interfaces ist, wird die Implementierung des Klasse, die dem Typ der Referenz entspricht, gerufen. Dieses Verhalten ist bei virtuellen Methoden gerade nicht so.
Methoden in Interfaces können abstract definiert werden
Wenn eine Klasse als abstract definiert ist, dürfen auch Methoden aus Interfaces (die in einer Klasse, die ein Interface implementiert, eigentlich auch implementiert sein müssen) als abstract definiert sein. In diesem Fall müssen diese Methoden in der Basisklasse nicht implementiert werden. Die abgeleiteten Klassen müssen die Methode dann implementieren. Damit könnte man z.B. in einer gemeinsamen Basisklasse sinnvolle Default-Implementierungen einer Teilmenge der Interface-Member implementieren während man von den abgeleiteten Klassen erwartet, dass sie die restlichen Member des Interfaces selbst implementieren.
Methoden in Interfaces können virtuell sein
Wie bei normalen Methoden (die kein Bestandteil eines Interfaces sind) kann eine Methode als virtual deklariert werden und verhält sich dann entsprechend. D.h. es wird immer die Implementierung in der tiefsten Ebene der Vererbungshierarchie gerufen, egal welchen Typ die Referenz hat, über die man die Methode aufruft.
Dazu muss die Methode in der Interface-Definition nicht virtual sein.
Es ist möglich, mehrere Interfaces zu implementieren, die die gleichen Member haben
Grundsätzlich kann eine Klasse einen gegebenen Member nur einmal implementieren. Nun ist es nicht unrealistisch, dass man in einer Klasse mehrere Interfaces implementiert und die Gefahr identischer Member in zwei oder mehr Interfaces ist durchaus real. Dieses Problem lässt sich einfach lösen, indem vor jeder Implementierung eines Members der Interfaces-Name vorangestellt wird. Diese explizite Qualifizierung muss dann auch beim Aufruf der Methode verwendet werden, sofern nicht eine Referenz vom Typ eines der Interfaces verwendet wird (sondern eine Referenz auf die konkrete Klasse).
Viele Grüße,
Andreas

