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.