gwizardry
gwizardry

Reputation: 511

How to set a base member generic List<T> using derived specific List<TUser>

I have a compiler error when trying to set a generic base collection class member in this derived class.

error CS0029: Cannot implicitly convert type 'System.Collections.Generic.List<IntSegment>' to 'System.Collections.Generic.List<T>'

Here's the outline of my generic collection

public class Path<T> : IEnumerable<T> where T : Segment
{
    private List<T> segments = new List<T>();

    public List<T> Segments
    {
        set { segments = value; }
        get { return this.segments; }
    }

    public Path()
    {
        this.Segments = new List<T>();
    }

    public Path(List<T> s)
    {
        this.Segments = s;
    }
}

A derived generic class of this collection is then defined for a derived class IntSegment of Segment (for which the base collection is defined)

public class IntersectionClosedPath<T> : Path<T>, IEnumerable<T> where T : IntSegment
{
    public IntersectionClosedPath(List<IntSegment> inEdges)
        : base()
    {
        Segments = inEdges;
    }
}

I can't understand why this assignment is not allowed. (I don't need to make a deep copy of the incoming List).

Upvotes: 0

Views: 655

Answers (3)

Kendall Frey
Kendall Frey

Reputation: 44376

A classic problem. A List<Derived> cannot be implicitly converted to a List<Base>.

You can cast the items in a List<Derived> and create a List<Base> like this:

listOfBase = listOfDerived.Cast<Base>().ToList();

Upvotes: 4

Tim S.
Tim S.

Reputation: 56556

Change List<IntSegment> inEdges to List<T> inEdges and it will work. The problem is that Segments is known as a List<T>, where T : IntSegment, while inEdges is a List<IntSegment>. (For reasons I'll not go into here unless you ask, such an assignment is not allowed. Look up variance/covariance/contravariance if you're interested.)

Upvotes: 5

Andras Zoltan
Andras Zoltan

Reputation: 42363

A List<T> is not equivalent to a List<TBase> where T : TBase.

Why? Because List<T> doesn't inherit from List<TBase>, only the generic type parameters are related.

You can instead do this in the constructor:

Segments = inEdges.Cast<Segment>().ToList()

I would also change the constructor parameter to IEnumerable<IntSegment>

Equally, it might be that @Tim S. has the best solution based on what you want to achieve. Personally I believe he's probably nailed it.

Upvotes: 3

Related Questions