C # - Problem mit Generika und Vererbung

7

Ich habe ein Problem mit Vererbung und Generika. Dies ist der Code, der mein Problem veranschaulicht:

%Vor%

Und wenn ich versuche, so etwas zu tun:

%Vor%

Ich erhalte Cast-Ausnahme: Ungültige Cast-Ausnahme. Kann 'TestApplication.MyClass'1 [System.Int32]' nicht in 'TestApplication.MyIntClass' umwandeln.

Außerdem kann ich keinen Darsteller erzeugen:

%Vor%

weil: 'TestApplication.MyIntClass.implicitate-Operator TestApplication.MyIntClass (TestApplication.MyClass)': benutzerdefinierte Konvertierungen zu oder von einer Basisklasse sind nicht zulässig

Ich muss Guss wie oben beschrieben erstellen. Ich weiß nicht, warum ich nicht von einem Typ, der die Basisklasse ist, casten kann. Wie kann ich dieses Problem lösen? Vielen Dank im Voraus.

Bearbeiten

Danke für Ihre Antworten. Jetzt sehe ich, dass ich nicht von einer Basisklasse in abgeleitete Klasse konvertieren kann und ich sehe, dass es nichts mit Generika zu tun hat. Aber warum kann ich keine benutzerdefinierten Konvertierungen von einer Basisklasse erstellen? Ich habe eine Methode, die die Basisklasse zurückgibt. Ich bin in der Lage, eine Konvertierungsmethode zu definieren, aber die Erstellung eines Cast-Operators imho wäre eine bessere Lösung.

    
empi 11.01.2009, 19:52
quelle

9 Antworten

12

Sie können nur von einer Basisklasse in eine abgeleitete Klasse umwandeln, wenn das Objekt tatsächlich vom Typ abgeleitete Klasse ist. Ich meine, Sie können keine Instanz der Basis ( MyClass<int> ) in MyIntClass umwandeln. Sie können es jedoch umwandeln, wenn es tatsächlich vom Typ MyIntClass als MyClass<int> -Instanz gespeichert wurde.

%Vor%

Angenommen:

%Vor%

Wenn es erlaubt wäre, was wäre der Wert von bar.y ? Tatsächlich ist die Konvertierung von Derived in Base überhaupt keine Konvertierung. Es teilt dem Compiler lediglich mit, dass die Variable vom Typ Base auf ein Objekt vom Typ Derived zeigen soll. Es ist möglich, da abgeleitet hat mehr oder gleiche Merkmale als Base , was nicht anders herum ist.

Wenn Sie einen Konvertierungsoperator zwischen Basis- und abgeleiteten Klassen erstellen könnten, wäre der C # -Compiler nicht in der Lage, ihn von den für sie definierten integrierten Beziehungen zu unterscheiden. Aus diesem Grund können Sie keine Darstellungsoperatoren entlang von Vererbungshierarchien erstellen.

    
Mehrdad Afshari 11.01.2009, 19:59
quelle
10

Die anderen Antworten sind bisher korrekt, aber ich möchte darauf hinweisen, dass Ihr Beispiel nichts mit Generika zu tun hat. Es ist das Äquivalent von:

%Vor%     
Jon Skeet 11.01.2009 20:08
quelle
2

In den Kommentaren, die Sie gefragt haben:

  

Aber warum ist die Konvertierung von einer Basisklasse nicht erlaubt?

Einfach - es würde keinen Sinn ergeben. Betrachten Sie das Beispiel:

%Vor%

Was glaubst du, würde dieses Programm ausgeben, vorausgesetzt, die Besetzung hat funktioniert? Noch schlimmer - stellen Sie sich vor, dass BaseClass zwei untergeordnete Klassen hat - ChildClassA und ChildClassB . Soll das funktionieren?

ChildClassA A = neue ChildClassA ();    Basisklasse bc = (Basisklasse) A;    ChildClassB B = (ChildClassB) bc;

Dies würde effektiv erlauben, ChildClassA Instanzen auf ChildClassB zu setzen - völlig falsch.

    
Vilx- 11.01.2009 20:29
quelle
0

Wie Mehrdad sagte, können Sie ein Objekt nicht verkleinern. Upcasting ist implizit, daher können Sie es nicht überschreiben.

Wie für den impliziten Operator können Sie immer noch einen Konstruktor in der abgeleiteten Klasse erstellen, der einen Parameter vom Typ baseclass empfängt.

Wenn Sie frei umwandeln müssen, definieren Sie die Variable als baseclass, instanziieren Sie abgeleitete Klassen.

    
devio 11.01.2009 20:05
quelle
0

Wie bereits gesagt, versuchen Sie, ein Objekt in einen Typ umzuwandeln, von dem es nicht abgeleitet ist. Wolltest du das vielleicht machen?

%Vor%     
Mike Scott 11.01.2009 20:16
quelle
0

Versuchen Sie anstelle der Erstellung einer MyIntClass einen Alias:

%Vor%

Dies ist jetzt gültig:

%Vor%

Bitte beachten Sie, dass Sie beim Ausführen des Alias ​​' using ' Ihren Namespace für den Namen des Alias-Typs (What.Ever.Namespace) qualifizieren müssen.

    
Will 11.01.2009 20:27
quelle
0

Bezüglich Ihrer zweiten Frage:

  

Aber warum kann ich keine benutzerdefinierten Konvertierungen von einer Basisklasse erstellen?

Nehmen wir an, Sie haben dieses Szenario

%Vor%

und du hast das versucht

%Vor%

sollte die Umwandlung aufgerufen werden? Natürlich nicht! Der Wert in x ist vom Typ Derived , also ist die Umwandlung direkt, ohne Konvertierung. Aber wenn der Wert nicht vom Typ Derived ist, sondern von einem konkreten Base , dann muss die benutzerdefinierte Konvertierung durchgeführt werden, da wir andernfalls einen Compilerfehler haben würden. Das alles macht keinen Sinn; Benutzerdefinierte Konvertierungen werden in der Kompilierungszeit gefunden, und der Typ des Werts von x ist nur in Laufzeit bekannt. Daher weiß der Compiler nicht, was zu tun ist - rufen Sie die benutzerdefinierte Konvertierung auf oder geben Sie einfach den Wert ein ...

Ich hoffe, das macht für Sie etwas Sinn.

    
configurator 11.01.2009 20:41
quelle
0

Beantworten Sie Ihre letzte Bearbeitung.

Dieser Code kompiliert bereits, er schlägt nur zur Laufzeit fehl:

  

MyIntClass intsth = (MyIntClass) etw;

Der folgende Umwandlungsoperator wäre also redundant, wenn explizit angegeben:

  

Öffentlicher statischer impliziter Operator MyIntClass (MyClass myClass)

Der Compiler sollte also verhindern, dass Sie diese Konvertierung hinzufügen. Ich denke, der Fehler mag verwirrend sein, aber ich denke, es verbietet es einfach, Klasse B in Klasse A umzuwandeln, wenn B von A abgeleitet ist (die Warnung schien mir zu verhindern, dass man zu A konvertiert).

Wenn der Operator implizit gemacht wird, ist das auch gefährlich, weil ein Downcasting immer fehlschlagen kann, also müssen Sie:

  1. zeigt den Compiler an, den Sie kennen, indem Sie eine explizite Umwandlung hinzufügen;
  2. zeigt dem Leser (der sich selbst, Minuten später) an, dass der Vorgang fehlschlagen könnte.
Blaisorblade 11.01.2009 21:59
quelle
0

Die Zuweisung / Konvertierung einer Basisklasse in eine abgeleitete Klasse ist sinnvoll, wenn Sie die Zuordnung oder Konvertierung als wertweisen Kopieren betrachten. Was ist verwirrend an c #? Neulinge ist die inkonsequente Art, wie es Dinge tut:

'int' ist ein 'einfacher' Typ:

%Vor%

'Objekt' ist kein einfacher Typ:

%Vor%

Wenn es eine Kopie von Werten würde, würde das Kopieren in die Basisklasse in eine abgeleitete Klasse erfolgen Arbeit. C # funktioniert nicht wie andere Sprachen.

Ich denke, das könnte Sie verwirren.

    
Jay 17.04.2009 16:17
quelle

Tags und Links