I'm trying to add a type-safe generically-typed container as a subtype of a non-generically-typed supertype.
It's for a compiler but for exposition, let me present it as as vehicle parts. You have a root class VehiclePart of which you can have normal subtypes (such as gearstick here) but apart can also contain sub-parts (such as PartContainer here), and I want to do this generically for compiler-checked type safety.
The code is below. It fails at newpc.Add();
and in return newpc;
My questions are
is this possible, and
is this even advisable?
There is something asymmetric about genericising a subtype that just smells bad. I've inherited these from a common superclass VehiclePart
because it should make handling them more consistent (if it can be made to work anyway. I'm rather a noob at generics) but it doesn't feel right.
public abstract class VehiclePart {
public abstract T cloneTypesafe<T>()
where T : VehiclePart, new();
}
public class Gearstick : VehiclePart {
public Gearstick() { }
public override T cloneTypesafe<T>() {
return new T();
}
}
public class PartContainer<T> : VehiclePart
where T : PartContainer<T>, new() {
private List<T> contents;
public PartContainer() {
contents = new List<T>();
}
public virtual void Add<U>(U newItem)
where U : T {
contents.Add(newItem);
}
public override U cloneTypesafe<U>()
// where U : T it doesn't like this
{
PartContainer<T> newpc = new PartContainer<T>();
foreach (var kid in contents) {
newpc.Add<U>(kid.cloneTypesafe<U>());
}
return newpc;
}
Edit: I was doing this wrong. The following code seems to do what I want, though I'm uncomfortable with it as I don't feel I understand it fully.
public class PartContainer2<K> : VehiclePart
where K : VehiclePart, new() {
private List<K> contents;
public PartContainer2() {
contents = new List<K>();
}
public virtual void Add(K newItem) {
contents.Add(newItem);
}
public PartContainer2<K> cloneTypesafe() {
PartContainer2<K> newpc = new PartContainer2<K>();
foreach (var kid in contents) {
newpc.Add(kid.cloneTypesafe<K>());
}
return newpc;
}
}