Ich bin auf diese in einem Lehrbuch gestoßen, das ich auf C # lese, aber ich habe Schwierigkeiten, sie zu verstehen, wahrscheinlich aufgrund mangelnden Kontexts.
Gibt es eine gute, präzise Erklärung dafür, was sie sind und wofür sie nützlich sind?
Zur Verdeutlichung bearbeiten:
Kovariante Schnittstelle:
interface IBibble<out T>
.
.
Kontravariante Schnittstelle:
interface IBibble<in T>
.
.
c#
.net
interface
covariance
contravariance
NibblyPig
quelle
quelle
Antworten:
Mit
<out T>
können Sie die Schnittstellenreferenz als eine in der Hierarchie nach oben behandeln.Mit
<in T>
können Sie die Schnittstellenreferenz in der Hiearchy als eine nach unten behandeln.Lassen Sie mich versuchen, es in mehr englischen Begriffen zu erklären.
Angenommen, Sie rufen eine Liste der Tiere aus Ihrem Zoo ab und beabsichtigen, sie zu verarbeiten. Alle Tiere (in Ihrem Zoo) haben einen Namen und eine eindeutige ID. Einige Tiere sind Säugetiere, einige sind Reptilien, einige sind Amphibien, einige sind Fische usw., aber sie sind alle Tiere.
Mit Ihrer Liste von Tieren (die Tiere verschiedener Arten enthält) können Sie also sagen, dass alle Tiere einen Namen haben, so dass es offensichtlich sicher wäre, den Namen aller Tiere zu erhalten.
Was ist jedoch, wenn Sie nur eine Liste von Fischen haben, diese aber wie Tiere behandeln müssen? Funktioniert das? Intuitiv sollte es funktionieren, aber in C # 3.0 und früher wird dieser Code nicht kompiliert:
Der Grund dafür ist, dass der Compiler nicht "weiß", was Sie mit der Tiersammlung beabsichtigen oder tun können , nachdem Sie sie abgerufen haben. Nach allem, was es weiß, könnte es einen Weg geben
IEnumerable<T>
, ein Objekt wieder in die Liste aufzunehmen, und dies würde es Ihnen möglicherweise ermöglichen, ein Tier, das kein Fisch ist, in eine Sammlung aufzunehmen, die nur Fisch enthalten soll.Mit anderen Worten, der Compiler kann nicht garantieren, dass dies nicht zulässig ist:
Der Compiler weigert sich also sofort, Ihren Code zu kompilieren. Das ist Kovarianz.
Schauen wir uns die Kontravarianz an.
Da unser Zoo mit allen Tieren umgehen kann, kann er mit Sicherheit auch mit Fischen umgehen. Versuchen wir also, unserem Zoo einige Fische hinzuzufügen.
In C # 3.0 und früheren Versionen wird dies nicht kompiliert:
Hier könnte der Compiler diesen Code zulassen, obwohl die Methode
List<Animal>
einfach zurückgegeben wird, weil alle Fische Tiere sind. Wenn wir also nur die Typen dahingehend geändert haben:Dann würde es funktionieren, aber der Compiler kann nicht feststellen, dass Sie dies nicht versuchen:
Da es sich bei der Liste tatsächlich um eine Liste von Tieren handelt, ist dies nicht zulässig.
Kontra- und Co-Varianz ist also, wie Sie Objektreferenzen behandeln und was Sie damit machen dürfen.
Die Schlüsselwörter
in
undout
in C # 4.0 kennzeichnen die Schnittstelle speziell als die eine oder andere. Mitin
können Sie den generischen Typ (normalerweise T) in Eingabepositionen einfügen, dh Methodenargumente und Nur-Schreib-Eigenschaften.Mit
out
können Sie den generischen Typ in Ausgabepositionen platzieren, dh Methodenrückgabewerte, schreibgeschützte Eigenschaften und Out-Methodenparameter.Auf diese Weise können Sie das tun, was mit dem Code beabsichtigt ist:
List<T>
hat sowohl In- als auch Out-Richtungen auf T, es ist also weder eine Co-Variante noch eine Contra-Variante, sondern eine Schnittstelle, mit der Sie Objekte wie das folgende hinzufügen können:würde Ihnen erlauben, dies zu tun:
Hier sind einige Videos, die die Konzepte zeigen:
Hier ist ein Beispiel:
Ohne diese Markierungen könnte Folgendes kompiliert werden:
oder dieses:
quelle
Dieser Beitrag ist der beste, den ich zu diesem Thema gelesen habe
Kurz gesagt, Kovarianz / Kontravarianz / Invarianz befasst sich mit automatischem Typgießen (von der Basis zur abgeleiteten und umgekehrt). Diese Typumwandlungen sind nur möglich, wenn einige Garantien in Bezug auf Lese- / Schreibaktionen, die an den gegossenen Objekten ausgeführt werden, eingehalten werden. Lesen Sie den Beitrag für weitere Details.
quelle