2012-03-27 23 views
1

Ich versuche, eine Liste von Objekten in einem Consturctor für eine IntersectionPath der Ableitungsklasse wie folgt zu werfen.Warum funktioniert Explicit Cast für generische Liste nicht

public class IntersectionPath : Path<IntersectionSegment>, IEnumerable 
    {   

     //Constructors 
     public IntersectionPath() : base() { Verts = null; } 

     public IntersectionPath(List<Intersection> inVerts, List<Segment<Node>> inEdges) : base() 
     { 
      this.Segments = (List<IntersectionSegment>) inEdges; 
     } 

    } 

Segmente werden in dem generischen Basisklasse Pfad definiert

public class Path<T> : IEnumerable<T> where T : Segment<Node> 
    { 
     //public properties 
     public List<Direction> Directions {get; set; } 
     public List<T> Segments { get; set; } 
    } 

Ich habe einen expliziten Operator für die Besetzung in der IntersectionSegment Klasse definiert (siehe unten und ist so unklar, warum wird dies nicht .. kompiliert ich eine Fehlermeldung für das Gießen im IntersectionPath Konstruktor

public class IntersectionSegment : Segment<Intersection> 
{   
    //curves which intersect the primary curve at I0(Start Node) and I1(End Node) 
    public Curve C0 { get; set; } 
    public Curve C1 { get; set; } 

    public IntersectionSegment():base() {} 

    public IntersectionSegment(Intersection n0, Intersection n1):base(n0,n1){} 

    public static explicit operator IntersectionSegment(Segment<Node> s) 
    { 
     if ((s.Start is Intersection) && (s.End is Intersection)) 
     { 
      return new IntersectionSegment(s.Start as Intersection,s.End as Intersection); 
     } 
     else return null; 
    } 

    public static explicit operator List<IntersectionSegment>(List<Segment<Node>> ls) 
    { 
     List<IntersectionSegment> lsout = new List<IntersectionSegment>(); 
     foreach (Segment<Node> s in ls) 
     { 
      if ((s.Start is Intersection) && (s.End is Intersection)) 
      { 
       lsout.Add(new IntersectionSegment(s.Start as Intersection,s.End as Intersection)); 
      } 
      else return null; 
     } 
     return lsout; 
    } 

Segment wird definiert als:

public class Segment <T> : Shape where T : Node 
{ 
    //generic properties 
    public T Start { get; set; } 
    public T End { get; set; } 

} 
+1

Sie haben eine Menge Code - können Sie versuchen, es auf ein kurzes, aber vollständiges Programm zu reduzieren? –

+0

Ich merke, dass .... Ich habe gerade in früheren Posts gefunden, ich werde für mehr Code gefragt! : -s – gwizardry

+1

Sie werden in der Regel für mehr gefragt, wenn Sie nicht * vollständigen * Code gegeben haben, aber kurz und vollständig ist in der Regel gut ... –

Antwort

7

List<InteractionSegment> ist nicht dasselbe wie InteractionSegment. Wenn Sie eine Liste eines Typs in eine Liste eines anderen Typs umwandeln, wird nicht jedes Element umgewandelt.
Sie brauchen so etwas wie dies zu tun:

this.Segments = inEdges.Select(x => (InteractionSegment)x).ToList(); 

Dies verwendet LINQ to Objects jedes Objekt in inEdges zu einem InteractionSegment Objekt zu werfen und legt das Ergebnis wieder in eine Liste, die dann zu this.Segments zugeordnet ist.

+0

OK danke. Ich bin mir nicht sicher, ob ich die Argumentation verstehe, da ich dachte, dass der Punkt der expliziten Besetzung, die ich geschrieben habe, darin bestand, dies zu überwinden. – gwizardry

+0

Sie haben eine explizite Umwandlung zwischen 'InteractionSegment' und 'Segment ' und ** nicht ** zwischen 'List ' und 'List >' geschrieben. Ihre explizite Besetzung ist für meinen Code weiterhin erforderlich und wird von diesem verwendet. –

+0

Ich dachte, ich hätte BEIDE geschrieben - bitte überprüfen. – gwizardry

2

Es funktioniert nicht einfach, weil ein List<Segment<Node>> kein List<IntersectionSegment> ist. Wenn Sie die später erstellen möchten, können Sie Ihre Cast() verwenden, um explizit jedes Element in der Liste nach Art zu werfen Sie wollen:

this.Segments = inEdges.Cast<IntersectionSegment>().ToList(); 
4

die an einem weit weniger verwirrend Beispiel aussehen lassen.

Ihre Frage ist ich glaube "Warum ist die Besetzung der letzten Zeile illegal?"

Nehmen wir an, es war legal. Jetzt fügen wir eine weitere Zeile hinzu:

animals.Add(new Tiger()); 

Sie können einen Tiger zu einer Liste von Tieren hinzufügen, richtig? Aber diese Liste von Tieren ist eigentlich eine Liste von Giraffen. Die Besetzung kopiert nicht die Liste, es sagt "Ich möchte dieses Objekt als von diesem Typ behandeln". Aber da du dadurch verrückte Dinge tun könntest, wie einen Tiger in eine Giraffenliste aufzunehmen, machen wir die Besetzung illegal.

Ihre Situation ist nur eine viel kompliziertere Version der gleichen Situation.

Diese Frage wird fast jeden Tag auf StackOverflow gestellt. Suchen Sie nach "Kovarianz und Kontravarianz" und Sie werden Dutzende von Beispielen finden.

+0

Ich sehe, dass Tiere nur eine variable Bezeichnung ist, die auf das gleiche Objekt wie Giraffen zugreift, das in der obigen Zeile neu definiert wurde. d. h. es ist nur eine Referenz. Wenn dies der Fall ist, was passiert mit einem neuen Objekt, das in einer legitimen expliziten Besetzung erstellt wurde (sagen wir, wenn wir eine für Animal anstelle der Liste erstellt haben)? – gwizardry

+0

@gwizardry: Wenn Sie einen benutzerdefinierten expliziten Konvertierungsoperator von 'Animal' nach' List 'machen wollen, ist das in Ordnung. Eine solche Umwandlung würde von einem "Tier" in eine "Liste " umwandeln, so dass Sie eine "Giraffe" in eine "Liste " umwandeln könnten. Aber das Ergebnis wäre keine "Liste ". –

+0

Nein, ich meinte Giraffe zu Animal. Aber meine Abfrage war mehr über die Logik, wenn wir ein neues Objekt zurückgeben (wie ich es in meinen Casting-Operatoren oben getan habe). Ändert das Ihre Beschreibung von "Behandeln Sie dieses Objekt als von diesem Typ" – gwizardry

Verwandte Themen