Ich habe kürzlich beschlossen, meinen Speicher bezüglich der C # Grundlagen aufzufrischen, also könnte das trivial sein, aber ich bin auf das folgende Problem gestoßen:
StringCollection
wurde in .NET v1.0 verwendet, um eine stark typisierte Sammlung für Strings zu erstellen, im Gegensatz zu object
based ArrayList
(dies wurde später durch die Aufnahme generischer Sammlungen erweitert):
Wenn Sie einen kurzen Blick auf StringCollection
definition werfen, können Sie Folgendes sehen:
Sie sehen es implementiert IList
, die die folgende Deklaration enthält (unter einigen anderen Deklarationen):
Aber nicht:
%Vor%Meine erste Annahme war, dass dies aufgrund der .NET-Framework-Kovarianzregeln möglich ist.
Um sicherzugehen, habe ich versucht, meine eigene Klasse zu schreiben, die IList
implementiert und
, um einen Stringtyp anstelle eines Objekttyps abzurufen, aber zu meiner Überraschung habe ich beim Kompilieren des Projekts einen Fehler bei der Kompilierung bekommen:
%Vor%Irgendwelche Ideen, was das verursacht?
Danke!
Das Verhalten wird durch die explizite Implementierung von IList.Add(object)
anstelle von co / contravariance verursacht. In der MSDN-Dokumentation implementiert StringCollection explizit IList.Add(object)
; Die Methode Add(string)
ist nicht verwandt. Die Implementierung ähnelt etwa so:
Diese Unterscheidung kann beobachtet werden:
%Vor%Zusatz
Das oben Gesagte behandelt nicht, warum dieses Muster implementiert wird. Die C # -Sprachspezifikation besagt, dass [§13.4.1, Hervorhebung hinzugefügt]:
In einigen Fällen ist der Name eines Schnittstellenelements möglicherweise nicht angemessen für die implementierende Klasse, in welchem Fall das Schnittstellenelement sein kann implementiert unter Verwendung einer expliziten Schnittstellenmember-Implementierung. [...]
Es ist nicht möglich, über einen vollständig qualifizierten Namen in einem Methodenaufruf, Eigenschaftenzugriff oder Indexerzugriff auf eine explizite Schnittstellenmemberimplementierung zuzugreifen. Auf eine explizite Schnittstellenmemberimplementierung kann nur über eine Schnittstelle zugegriffen werden Instanz, und wird in diesem Fall einfach durch seinen Mitgliedsnamen referenziert.
StringCollection hält sich an das erforderliche IList-Verhalten - IList gibt keine Garantie dafür, dass ein beliebiges Objekt hinzugefügt werden kann. StringCollection gibt stärkere Garantien - in erster Linie, dass es nur Zeichenfolgen enthält. Die Klasse enthält eigene stark typisierte Methoden für Add
, Contains
, Item
und andere für den Standard-Anwendungsfall, in dem auf sie als StringCollection
und nicht als IList
zugegriffen wird. Aber es funktioniert immer noch perfekt als IList
, akzeptiert und gibt Objekte zurück, gibt aber einen Fehlercode zurück (wie IList erlaubt), wenn versucht wird, ein Element hinzuzufügen, das keine Zeichenkette ist.
Letztendlich liegt es im Ermessen des Klassenautors, ob eine Schnittstelle in der Klasse auftaucht (d. h. explizit implementiert wird). Im Fall von Framework-Klassen sind explizite Implementierungen in der MSDN-Dokumentation enthalten, aber nicht als Klassenmitglieder verfügbar (z. B. in Autokomplettierungskontexten).
Wenn Sie .net 2.0+ verwenden, würde ich nur Generika verwenden:
%Vor%Das sollte dir alles geben, was du willst.
IList.Add(object)
kann andere Parameter als Strings akzeptieren - es kann jeden beliebigen Typ annehmen. Wenn Sie also Ihre Implementierung der Schnittstelle so deklarieren, dass sie nur Zeichenfolgen akzeptiert, stimmt sie nicht mehr mit der Schnittstellenspezifikation überein, weil ich zum Beispiel kein Stream
übergeben konnte.
Die Varianz kann die andere -Weise verwenden: Wenn die Interface-Methode zum Akzeptieren von Strings deklariert wurde, dann wäre das Akzeptieren von Objekten in Ordnung, da Strings ebenfalls Objekte sind und somit auch jede Eingabe für die Methode der Schnittstelle akzeptabler Input für Ihre Implementierung sein. (Sie müssen jedoch immer noch eine explizite Schnittstellenimplementierung mit einer Methode bereitstellen, die einen String akzeptiert, da in C # eine Schnittstellenmethodenimplementierung genau der Deklaration der Schnittstellenmethode entspricht.)
Was IList
im Grunde angibt, ist, dass Sie Add
aufrufen und jedes Objekt als Parameter übergeben können, von einem eingerahmten Int
zu einem anderen IList
zu einem System.DivideByZeroException
. Wenn Sie nur eine Add( string )
-Methode angeben, haben Sie diese Anforderung nicht erfüllt, da Sie nur Zeichenfolgen hinzufügen können.
Mit anderen Worten, Sie könnten StringCollection.Add( new Object() );
nicht aufrufen, was perfekt möglich wäre, wenn die Schnittstelle korrekt implementiert wäre. : D
Tags und Links .net c# inheritance covariance interface