Question

I am trying to cast a list of objects within a consturctor for a derive class IntersectionPath as follows.

    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;
        }

    }

Segments is defined in the generic base class Path

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

I have defined an explicit operator for the cast within the IntersectionSegment class (see below and so am unclear as to why this won't compile. I have an error message for the casting within the IntersectionPath constructor.

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 is defined as:

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

 }
Was it helpful?

Solution

List<InteractionSegment> is not the same as InteractionSegment. Casting a list of one type to a list of another type won't cast each item.
You need to do something like this:

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

This uses LINQ to Objects to cast each object in inEdges to an InteractionSegment object and puts the result back into a list that is then assigned to this.Segments.

OTHER TIPS

Let's look at a far less confusing example.

class Animal {}
class Giraffe : Animal {}
class Tiger : Animal {}
...
List<Giraffe> giraffes = new List<Giraffe>();
List<Animal> animals = (List<Animal>) giraffes; // illegal

Your question is I believe "why is the cast on the last line illegal?"

Let's suppose it was legal. Now we add another line:

animals.Add(new Tiger());

You can add a tiger to a list of animals, right? But that list of animals is actually a list of giraffes. The cast does not copy the list, it says "I want to treat this object as being of this type". But since doing so would allow you to do crazy things like putting a tiger into a list of giraffes, we make the cast illegal.

Your situation is just a much more complicated version of the same situation.

This question gets asked almost every day on StackOverflow. Look for "covariance and contravariance" and you will find dozens of examples.

It doesn't work simply because a List<Segment<Node>> is not a List<IntersectionSegment>. If you want to create the later your can use Cast() to explicitly cast each item in the list to the type you want:

this.Segments = inEdges.Cast<IntersectionSegment>().ToList();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top