Wie behandelt c # verschachtelte (generische) Typen?

8

Ich versuche zu verstehen, wie C # Typen angesichts der Verschachtelung anzeigt.
Genauer gesagt versuche ich zu verstehen, warum einige Typen nicht als zuweisungskompatibel oder sogar gießbar angesehen werden, wenn es "irgendwie" nur eine Definition der verschachtelten Klasse gibt. Erzeugt der Compiler / CLR tatsächlich unterschiedliche Typen für diese oder welche Regeln spielen genau ...

Beispielcode:

%Vor%

Auch wenn die geschachtelte Instanz als Private2.Nested erstellt wird, kann sie nicht an diesen Typ übergeben werden. Und ... naja ... wie hängen die verschiedenen verschachtelten Typen zusammen, da Nested tatsächlich versiegelt ist? (Sie können nicht voneinander erben, richtig? Aber auf der anderen Seite sollte ihre Umsetzung zu 100% identisch sein ... liege ich falsch?)

Primäre Frage: Was genau tut der Compiler, wenn er diese verschachtelte Klasse "kompiliert"? Wie viele eindeutige Typen (mit Ausnahme von Wertetyp-bezogenen) werden tatsächlich generiert, und wenn es sich um den gleichen Typ handelt, ist die Einschränkung künstlich (wie wäre es nicht mit einer unsicheren Besetzung?)? (Was ich sagen will, ist, dass die IL für all diese Typen von derselben Code-Definition kommt - also muss der Compiler auf einer bestimmten Ebene wissen. Sind Instanzen dieser Typen nicht Bit-für-Bit identisch mit ihren Typnamen?)

Sekundäre Frage: Nicht das, was ich hier wirklich frage, hauptsächlich aus Gründen der Kürze / des Kontextes: Gibt es eine einfache Änderung, die das oben genannte funktioniert? Fehle ich etwas Offensichtliches?

Der Typ Foo<T> darf niemals direkt in Private1<T2> referenziert werden - nur die Verwendung von T2 ist erlaubt. Foo<T> ist nur mein Beispiel für böse generische Klassen mit 10 ~ 20 generischen Typen. Es ist alles nur ein "Workaround", um eine generische Klasse mit ihren Typen nicht zu aliasieren:

%Vor%

Zweck: Vermeidung von Typen von Feldern und Methodenparametern, die mehrere Bildschirme breit sind und absolut nicht lesbar sind! & gt; :(

... Als Randnotiz wünschte ich mir wirklich, dass this als Typ innerhalb von Klassen und Interfaces verwendet werden könnte, wie in Private2 : Private1<this> . Nun gut, das würde nicht funktionieren, weil es mit der Extensionssyntax auf Methoden kollidiert, aber etwas ähnliches, vielleicht <this> , <super> , <base> verwendet wie Method(<this> arg) oder Private2 : Private1<<super>> ... irgendwie komisch vielleicht.

    
AnorZaken 27.02.2015, 21:52
quelle

3 Antworten

2

Betrachte diese Typen:

%Vor%

Was ist Derived.Value und Derived.Nested . Wenn Sie vererbte statische Member (geschachtelte Klassen, die als statisches Member betrachtet werden) durch abgeleitete Klassen referenzieren, verweisen Sie nur auf Basisklassenmitglieder. Diese haben also genau die gleiche Bedeutung wie Base.Value und Base.Nested zur Kompilierzeit. Es gibt kein separates statisches Feld Derived.Value oder separate Klasse Derived.Nested .

%Vor%

Ursprüngliche Antwort:
Foo<A>.Private1<B>.Nested und Foo<C>.Private1<D>.Nested werden als unterschiedliche Typen betrachtet, wenn A ! = C oder B ! = D . Sie können dieselbe Implementierung intern verwenden, aber für die Zuordnungskompatibilität sind sie unterschiedlich. Foo<T>.Private2.Nested ist nur ein Alias ​​für Foo<T>.Private1<Foo<T>>.Nested . Und selbst wenn class Bar:Foo<A>{} , werden die Klassen Foo<A>.Private1<Foo<A>>.Nested und Foo<A>.Private1<Bar>.Nested immer noch als unterschiedliche Typen betrachtet. Daher kann Foo<T>.Private1<T2>.Nested nicht in Foo<T>.Private1<Foo<T>>.Nested konvertiert werden, da T2 nicht erforderlich ist Foo<T> .

    
PetSerAl 28.02.2015, 00:39
quelle
1

Sie denken nicht mit Portalen. Ihre inneren Klassen sind bereits auf T verallgemeinert.

%Vor%     
antiduh 27.02.2015 22:14
quelle
0

Teilantwort auf die primäre Frage:

Es störte mich, dass Sie den Code kompilieren können, indem Sie Method2 so ändern, dass ein Objekt akzeptiert und zur Laufzeit umgewandelt wird, weil die geschachtelte Instanz vom richtigen Typ ist (sie ist in Method1 instanziiert). Das scheint zu funktionieren - solange Foo versiegelt ist - aber sobald jemand anderes Private1 ableiten kann, ist es nicht mehr garantiert, dass es funktioniert. (Und somit keine Lösung.) Allerdings zeigt das Testen dieses Ansatzes:

  
    

Private2.Nested ist nur ein Konstrukt von Syntaxregeln - die Verwendung von GetType() für die resultierende Variable sagt Private1.Nested und es gibt keine Private2.Nested type.

  

Ich denke, dass das unangenehme Gefühl, das ich daraus ziehen konnte (und warum ich versiegelte, verwandt zu sein), eine gewisse Verwirrung meinerseits war, als es darum ging, zwischen Subtyp und Vererbung zu unterscheiden. Da die äußeren Klassen erben (Private1 und Private2), fühlt es sich an wie Vererbung, und es fühlt sich so an, als ob es irgendwie castable sein könnte. Aber wenn ich das richtig verstehe, sind sie nur vom selben Subtyp:

  
    

Es muss keine Vererbungsbeziehung geben oder gibt es in der einen oder anderen Weise (wie die Versiegelung deutlich andeutet), weil "die Vererbungshierarchie unterscheidet sich von der Subtyphierarchie ", und somit wäre eine regelrechte Konvertierung erforderlich (da Abbilder an die Vererbungshierarchie gebunden sind).

  
    
AnorZaken 03.03.2015 08:34
quelle

Tags und Links