2016-06-07 9 views
0

Ich habe dieses Setup, und es hat nicht funktioniert, wie ich erwartet hatte. Es scheint mir, dass ein generisches T in einer Basisklasse nicht dasselbe ist wie das generische T in seiner Unterklasse.C# und Vererbungskette von mehreren Typen mit Generics

namespace StackOverflowQuestion 
{ 
    public class Poco1 
    { 
     public string Data { get; set; } 
    } 

    public class Poco2 : Poco1 
    { 
     public string ExtraData { get; set; } 
    } 

    public class Poco3 : Poco2 
    { 
     public string EvenMoreData { get; set; } 
    } 


    public class Base<T> where T: Poco1 
    { 
     public virtual void Method(T parameter) 
     { 
      // Do something even more general with Data... 
      parameter.Data = "Test"; 
     } 
    } 

    public class FirstLevel<T> : Base<Poco2> where T:Poco2 
    { 
     public override void Method(Poco2 parameter) 
     { 
      // Do something general with ExtraData... 
      base.Method(parameter); 
     } 
    } 

    public class SecondLevel<T> : FirstLevel<Poco3> where T: Poco3 
    { 
     public override void Method(Poco2 parameter) // <-- Why not Poco3? 
     { 
      // Do something with EvenMoreData... 
      base.Method(parameter); 
     } 
    } 
} 

Was ich eigentlich war zu erwarten, dass die Method Überschreibung in Art SecondLevel<T>Poco3 sagen sollte und nicht Poco2. Zumal ich eine Einschränkung für T auf den Typ Poco3 gesetzt habe.

Kann dies auf andere Weise erreicht werden? Es scheint mir, dass die generische T nicht "" überschrieben werden kann, wie ich wollte. Ich vermute T in Base<T> ist nicht das gleiche wie T in FirstLevel<T> und dass T in FirstLevel<T> ist nicht das gleiche wie T in SecondLevel<T>?

Wenn SecondLevel<T> erbt von Base<T> dann bekomme ich Poco3 im Method überschreiben, aber nicht, wenn ich von FirstLevel<T> erben.

Ich kann mit diesem Problem leben, aber dann muss ich den poco-Parametertyp in Level-Typ-Unterklassen (ab Level 2 und höher). Meiner Meinung nach sollte das unnötig sein, solange ich die Beschränkung festlege. Aber, natürlich, könnte es einen guten Grund für dieses Verhalten geben, das ich im Moment nicht sehe.

+1

Verwenden Sie diese Signatur für alle erbenden Typen: öffentliche Überschreibung void Methode (T-Parameter) – AndyJ

+0

@AndyJ Du bist mein Held! Natürlich, warum habe ich das nicht gesehen? Wenn Sie meinen Code einfügen und jede Poco-Referenz (außer in den Constraints) durch T ersetzen, werde ich das sofort als Antwort markieren :) – Frode

Antwort

2

Anstatt den POCO-Typ in jeder überschriebenen Methodensignatur anzugeben, können Sie stattdessen den T-Typ-Parameter verwenden.

T ist bereits auf den gewünschten POCO-Typ beschränkt, so dass es sich genau so verhalten sollte, wie Sie es möchten.

Oh, und ich würde dasselbe mit dem Typ tun, den Sie auch an die Basisklasse übergeben.

z.B.

public class FirstLevel<T> : Base<T> where T:Poco2 
{ 
    public override void Method(T parameter) 
    { 
     // Do something general with ExtraData... 
     base.Method(parameter); 
    } 
} 

public class SecondLevel<T> : FirstLevel<T> where T: Poco3 
{ 
    public override void Method(T parameter) 
    { 
     // Do something with EvenMoreData... 
     base.Method(parameter); 
    } 
} 
+0

Danke, Mann. Es ist mein erster Versuch, Typen mit generischen Argumenten auf mehr als zwei Ebenen zu erben. Es ist so offensichtlich, als ich deine Antwort sah. – Frode

+0

Keine Probs. Ich habe gerade die Antwort so bearbeitet, dass ich auch den Typparameter T für die Übergabe an die Basisklasse vorgeschlagen habe. Dann ist T ganz runter, heh. – AndyJ

+0

Habe den ganzen Tag mit diesem Thema gekämpft. Jetzt habe ich heute etwas Wesentliches Neues gelernt. Perfekt! – Frode