Warum kann eine Schnittstelle keine Typen enthalten?

8

Das hat mich in C # ein- oder zweimal erwischt. Ich kann Code wie diesen schreiben

%Vor%

aber wenn ich schreibe

%Vor%

Ich bekomme den Kompilierfehler

  

Fehler CS0524: 'Verbindung': Schnittstellen können keine Typen deklarieren

Ich verstehe die Einschränkung, aber was mich interessiert, ist warum . Ich kann sicherlich verschachtelte Typen in einer C ++ "Schnittstelle" haben (was nur eine Klasse mit abstrakten Mitgliedern ist, also keine Überraschung), und anscheinend ist es auch in Java möglich, siehe Interfaces kann keine Typen deklarieren und Warum kann ich einen Delegaten nicht in eine Schnittstelle einfügen? < Aber sie schienen meine Frage nicht direkt anzusprechen.)

Bearbeiten

Ich dachte, ich würde einfach eine Notiz hinzufügen, um zu sagen, dass es in der Java-Welt auf den ersten Blick eine offene Frage ist, ob es in Ordnung ist, eine Klasse in eine Schnittstelle zu verschachteln. Siehe Ссылка . Ich denke nicht, dass ich dumm bin zu fragen, warum das nicht für C # gelten kann.

Bearbeiten

Kurze Zusammenfassung / Zitate aus Framework Design Guidelines , 2ed, Abschnitt 4.9, S.115-117.

  • Verwenden Sie geschachtelte Typen, wenn z. Der verschachtelte Typ benötigt Zugriff auf private Member des umschließenden Typs.
  • Verwenden Sie nicht den öffentlichen geschachtelten Typ zum Gruppieren. Verwenden Sie dafür Namespaces.
  • Vermeiden Sie öffentlich verschachtelte Typen, es sei denn, Sie wissen wirklich, was Sie tun. (Hauptmotivation: das explizite Erstellen verschachtelter Typen ist für weniger erfahrene Entwickler verwirrend. Das implizite Erstellen, z. B. über Auflistungs-Enumeratoren, ist jedoch in Ordnung.)
  • Verwenden Sie keine geschachtelten Typen, wenn der verschachtelte Typ außerhalb des enthaltenen Typs verwendet oder instanziiert wird (beide Argumente sprechen für die Unabhängigkeit des geschachtelten Typs vom enthaltenden Typ).
  • Verwenden Sie nicht als Mitglied einer Schnittstelle.
TooTone 22.04.2013, 16:06
quelle

4 Antworten

29
  

Warum kann eine Schnittstelle keine Typen enthalten?

Bevor ich mich der Frage zuwende, lasst mich ein paar Dinge klären.

Zunächst erlaubt das CLR-Typsystem geschachtelte Typen innerhalb von Schnittstellen . Es wäre durchaus möglich, eine Version von C # oder VB oder was auch immer morgen zu erstellen, die Interfaces, Delegates, Klassen, Structs und Enums unterstützt, die in Interfaces deklariert werden, und es würde auf der vorhandenen CLR laufen.

Zweitens werde ich Ihnen meinen üblichen Pushback auf Fragen des Formulars geben: "Warum implementiert die C # -Sprache nicht Feature X?" Die Antwort ist für alle Werte von X gleich. Um implementiert zu werden, muss ein Merkmal sein: gedacht, entworfen, spezifiziert, implementiert, getestet und an Kunden ausgeliefert. Wenn eines dieser sechs Dinge nicht passiert, dann gibt es kein Feature. Feature X ist nicht implementiert, weil eines oder mehrere dieser Dinge nicht aufgetreten sind.

Drittens muss das C # -Compiler-Team (auf dem ich nicht mehr aktiv bin) keine Erklärung dafür liefern, dass nicht ein Feature implementiert. Merkmale kosten Geld, das Budget ist begrenzt, und daher liegt es an der Person, die das Merkmal anfordert, ihre Vorteile gegen ihre Kosten zu rechtfertigen.

Viertens, "warum" Fragen sind schwer zu beantworten und "warum nicht" Fragen sind noch schwieriger.

Also, damit einverstanden, werde ich Ihre Frage ablehnen und sie durch eine Frage ersetzen, die ich beantworten kann:

  

Angenommen, diese Featureanforderung wurde dem C # -Designteam vorgeschlagen. Welche Argumente hätten Sie dagegen gemacht?

  • Die Funktion ist zwar in der CLR legal, im CLS jedoch nicht zulässig. Es gibt viele Funktionen in C #, die im CLS nicht zulässig sind, aber da die CLS-Anleitung speziell keine Typen in Schnittstellen verschachtelt, da die meisten Sprachen dies nicht unterstützen , ist die Implementierung des Features in C # wesentlich Menschen ermutigen, Bibliotheken zu schreiben, die nicht in anderen Sprachen verwendet werden können. Die vorgeschlagene Funktion fördert eine schlechte Programmierpraxis .

  • Verschachtelte Typen bieten Ihnen drei Hauptvorteile. Erstens haben sie Zugriff auf die privaten Mitglieder ihrer umschließenden Typen. Dies ist kein Vorteil für Schnittstellen, die keine privaten Mitglieder haben. Zweitens bieten sie eine bequeme Möglichkeit, ein spezifisches privates Implementierungsdetail des äußeren Typs zu enthalten. Dies ist kein Vorteil für Schnittstellen, die vermutlich keinen privaten verschachtelten Typ haben könnten und die per Definition keine Implementierungsdetails aufweisen. Drittens bieten sie eine bequeme Möglichkeit, einen Typ mit einem anderen zu verbinden. Dies ist jedoch besser durch Namespaces möglich.

  • Niemand sonst, der mich interessiert, fordert das Feature an. Wir sollten kein Geld für ein Feature ausgeben, das kaum jemand möchte, wenn es viele Funktionen gibt, die die Kunden brauchen.

  • Die Implementierung der Funktion macht die Sprache in keiner Weise leistungsfähiger oder aussagekräftiger.

  • Die Implementierung der Funktion ist kein Sprungbrett für eine weitere tolle Funktion, die mir bekannt ist. Die Funktion passt nicht zu einem anderen "Thema". Es ist eine "Completionist" -Funktion, die eine kleine Nicht-Orthogonalität beseitigt, keine nützliche Funktion.

  • Es gibt eine einfache Problemumgehung für das Fehlen der Funktion; Machen Sie den geschachtelten Typ einfach zu einem Typ auf oberster Ebene.

Das ist der Fall gegen . Ohne jemanden, der einen Fall für das Feature voranbringen kann, wird es in der Sitzung des Designkomitees nicht länger als fünf Minuten dauern. Möchten Sie einen Fall für das Feature voranbringen?

    
Eric Lippert 22.04.2013, 19:17
quelle
2

Es gibt nur wenige Gründe, warum es sinnvoll ist, Typen zu verschachteln. Der Hauptgrund besteht darin, sie als privat zu definieren, sodass nur die Containerklasse darauf zugreifen kann. Die Containerklasse würde diese privaten Typen in ihren eigenen Implementierungen verwenden.

Da eine Schnittstelle keine Implementierung ist, gibt es keinen Grund, Typen darin zu verschachteln. Es wäre nutzlos. Es wäre wie ein Bauer, der versucht, ein Kätzchen zu benutzen, um ihm beim Pflügen seiner Felder zu helfen. Theoretisch könnte das zumindest möglich sein, aber es würde keinem praktischen Zweck dienen.

Wenn ich den bereitgestellten Code betrachte, würde ich vorschlagen, die Klasse Connection zu einem Top-Level-Typ zu machen. Wenn Sie Ihre Typen nach Funktionen organisieren möchten, sind dies die Namespaces. Erstellen Sie in Ihrem Projekt eine Ordnerstruktur, in der die Typen organisiert sind, und ändern Sie die Namespaces entsprechend.

    
Dan 22.04.2013 16:17
quelle
1

Aus der C # Spezifikation, Abschnitt 13.2:

  

Eine Schnittstelle darf keine Konstanten, Felder, Operatoren, Instanzkonstruktoren, Destruktoren oder Typen enthalten, noch kann eine Schnittstelle statische Elemente enthalten.

Verschachtelte Typen sind eine Art statisches Member, daher ist es konsequenter, verschachtelte Typen nicht zuzulassen, als sie zu einem Sonderfall zu machen.

    
mike z 22.04.2013 16:19
quelle
1

Obwohl es in einem Kommentar zu diesem Beitrag erwähnt wurde, möchte ich hier noch einmal darauf hinweisen, dass Sie VB.Net verwenden können, um Schnittstellen mit verschachtelten Typen zu erstellen, und diese Schnittstelle und alle darin geschachtelten Typen in C # uneingeschränkt zu verwenden. Sie können diesen Code auch mithilfe eines Tools wie ILDasm oder ILSpy in IL exportieren und dann mithilfe der Visual Studio ILSupport-Erweiterung in Ihre Bibliothek zurückverwandeln (vorausgesetzt, Sie benötigen sie nicht direkt in Ihrer Bibliothek).

Aus Gründen, warum jemand dies tun möchte, hier sind zwei. Die erste besteht darin, die Blueprint- / Musterdefinitionen für eine Gruppe von gekoppelten Schnittstellen mit gemeinsamen generischen Typparametern bereitzustellen, die zur Unterstützung eines gemeinsamen Konzepts erforderlich sind, z. B. Entitätsverwaltung. Zum Beispiel:

%Vor%

Das Obige könnte alternativ gelöst werden, indem die generischen Typparameter und Einschränkungen für jede verschachtelte Schnittstelle / Klasse außerhalb der Containerschnittstelle wiederholt werden, aber das wird schnell unordentlich. Eine andere großartige Alternative wäre, wenn .Net generische Typparameter für Namespaces unterstützt, aber leider wird das nicht unterstützt.

Der zweite Grund für die Verschachtelung von Typen in einer Schnittstelle wäre die Bereitstellung einer Kompositions- / Mixin-Schnittstelle zum Definieren von zusammengesetzten Schnittstellen und einer geschachtelten unterstützenden Komponiererklasse, die Funktionen zum Akzeptieren von Mixin-Instanzen zum Erstellen einer neuen dynamischen Klasse bereitstellt, die die zusammengesetzte Schnittstelle und Weiterleitungen implementiert die Anrufe zu den Mixins. Wie das folgende:

%Vor%

Sie könnten dann Schnittstellen erstellen, die die obige IComposite-Schnittstelle erweitern, die bereits einen geeigneten Composer für die erweiterte Schnittstelle enthalten würde. Beachten Sie, dass Sie wahrscheinlich auch andere Varianten der IComposite-Schnittstelle haben, um höhere Zählungen von Mixins zu unterstützen (ähnlich wie Func und Action, da .Net derzeit keine variablen generischen Typparameter unterstützt).

Sie können es wie im folgenden Beispiel verwenden:

%Vor%

Obwohl es möglich ist, die Composer-Klasse außerhalb der IComposite-Schnittstelle zu erstellen, ist die Ermittlung der Kompositionsunterstützung oder -absicht nicht so einfach wie das Erscheinen des Composers in IntelliSense. In diesem Fall wird die verschachtelte Composer-Klasse tatsächlich verwendet, um eine statische Methode (Create) für die Schnittstelle bereitzustellen (was eine andere nicht unterstützte Option ist).

    
Tyree Jackson 22.07.2015 19:29
quelle

Tags und Links