Home > OS >  Cast a list of derived types when casting the parent derived class to it's base type
Cast a list of derived types when casting the parent derived class to it's base type

Time:10-15

I have simplified the code for brevity.

There are two base classes, Document and Line and two classes derived from those, DocumentPlus and LinePlus.

Document and DocumentPlus contain a List<Line> and List<LinePlus> respectively.

public class Test
{

    public class Document
    {
        public List<Line> Lines = new List<Line>();
    }

    public class Line
    {
        public string? A;
    }

    public class DocumentPlus : Document
    {
        public new List<LinePlus> Lines = new List<LinePlus>();
    }

    public class LinePlus : Line
    {
        public string? B;
    }
        
    public Test()
    {
        var x = new DocumentPlus();
        x.Lines = new List<LinePlus>()
        {
            new LinePlus() { A = "123", B = "456" },
            new LinePlus() { A = "789", B = "101" },
            new LinePlus() { A = "112", B = "131" }
        };

        var y = (Document)x;

        var z = y.Lines;
        // Z should be the Lines entered above but as their base type
        // Just not sure how to do it!

    }

}

Is there any way I can cast the List<LinePlus> to List<Line> when casting a DocumentPlus instance to Document?

Thanks!

CodePudding user response:

Is there any way I can cast the list of LinePlus to Line when casting a DocumentPlus instance to Document?

No, because the List<LinePlus> belongs to DocumentPlus and not Document.

DocumentPlus uses the new keyword when declaring Lines. This indicates that you want to use method hiding rather than overriding; Document.Lines is still of type List<Line> and does not reference the same instance as DocumentPlus.Lines.

In fact they can't reference the same instance because List<LinePlus> is unrelated to List<Line>, considering List<T> is generically invariant.


If you simply want to convert DocumentPlus.Lines to a List<Line>, then that's perfectly possible:

var z = x.Lines.ConvertAll(linePlus => (Line)linePlus);

But it seems that your intended inheritance hierarchy is broken.

CodePudding user response:

Try this.

using System.Linq

public Document CastDocPlusToDoc(DocumentPlus inputDocP) {
    Document outputDoc = new Document();
    outputDoc.Lines.AddRange(inputDocP.LinesPlus.Cast<Lines>());
}

var y = CastDocPlusToDoc(x)

I'm not even sure that .Cast is necessary here

CodePudding user response:

The (possible) "correct" way to approach this is with generics - then no casting is required. You just get the right type of Line when enumerating the collection.

public class Document<TLine> where TLine : Line
{
    public List<TLine> Lines = new List<TLine>();
}

public class Line
{
    public string? A;
}

public class DocumentPlus : Document<LinePlus>
{
}

public class LinePlus : Line
{
    public string? B;
}

Live example: https://dotnetfiddle.net/BbfOAN


As commented, this might more closely suit your requirements

public class DocumentBase<TLine> where TLine : Line
{
    public List<TLine> Lines = new List<TLine>();
}

public class Line
{
    public string? A;
}

public class Document : DocumentBase<Line>
{
}

public class DocumentPlus : DocumentBase<LinePlus>
{
}

public class LinePlus : Line
{
    public string? B;
}
    

This approach gives you type safety, and thus does not require you to cast to LinePlus when dealing with DocumentPlus instances.

  • Related