- Home /
C# Generic Type Inheritance
Hey everyone. I have some problems with the inheritance of Generic classes. In the example below there is a exception thrown when I try to initialize the List.. It seems like it can't cast from MiningBuilding (Building) to Building. I've heard that this should be possible in Java. Does anyone see a solution for this?
Not tested Code:
abstract class BuildingType : ScriptableObject{ }
class MiningBuildingType : BuildingType { }
abstract class Building<T> where T : BuildingType
{
public T Type;
}
class MiningBuilding : Building<MiningBuildingType>
{
public MiningBuilding(T type)
{
Type = type;
}
}
..
public MiningBuildingType type;
List<Building<BuildingType>> buildings = new List<Building<BuildingType>>(){ new MiningBuilding(type) };
Very strange pattern, in unity you would like to use composition whenever you can. Looking at your snippet it can be syntax error, there are misssing parentecices in list declaration...
List<Building<BuildingType>> buildings = new List<Building<BuildingType>>(){ new $$anonymous$$iningBuilding() };
Yeah, that's not actual code. I just wrote that to show the problem. I'm using composition. But I want the Field in $$anonymous$$iningBuilding to be of type $$anonymous$$iningBuildingType. That field is decalred in its base class (Building) of type BuildingType.
Do you get what im trying to say?
I just don't get what do you want to achieve b saying "$$anonymous$$iningBuiulding of $$anonymous$$iningBuildingType". It sounds very strange. Every class itself IS a type, at least this is how I am reasoning about them. Talking about Unity, you also should take into consideration $$anonymous$$onoBehaviours (as a front-end for your data structure) then maybe wrap your underlying data structure with scriptable objects containers.
List<Building<BuildingType>> buildings = new List<Building<BuildingType>>(){ new $$anonymous$$iningBuilding() };
I mentioned missing parenteces befor, its just got eaten by comment editor :(
Answer by Firas4d · May 07, 2018 at 01:48 PM
Hi, To simplify your example allow me to take the list and the generic definition out of the equation. What you are trying to do is casting a class to another incompatible class implicitly without providing a mechanism telling the compiler how to do the casting.
Class A {}
Class B {}
...
A obj = new B();
The code above will generate the same error you got because A and B are 2 separate types.
To solve this error you have 2 options, either you implement a user defined type conversion like this
public class B
{
public static implicit operator A(B obj)
{
return new A();
}
}
or you just simply make B inherits from A.
Now lets get back to the generic class definition, take a look at the following example
//Behaviour is a Unity class where MonoBehaviour inherits from
Class A<T> where T : Behaviour {}
A<Behaviour> aBehaviour = new A<MonoBehaviour>();
this will not compile successfully because the generic class A(Behaviour) is completely different than A(MonoBehaviour) even though MonoBehaviour is related to Behaviour and both types are supported by class A.
Put all that aside, IMO I see no need to have a generic class in your case, it just makes your code unnecessarily complicated. If you just do the following all will be fine.
Class Building {}
Class MiningBuilding : Building {}
Answer by misher · May 07, 2018 at 12:55 PM
You can't have a constructor like this:
class MiningBuilding : Building<MiningBuildingType>
{
public MiningBuilding(T type)
{
Type = type;
}
}
MiningBuilding could only have field "Type" of type MiningBuildingType (type of type lol)
class MiningBuilding : Building<MiningBuildingType>
{
public MiningBuilding()
{
Type = new MiningBuildingType();
}
}
Now declaring a List like this:
List<Building<BuildingType>>
won't let you to create it, because you can't create any instance of abstract class (building)
Adding intermediate building class can enable you to create generic list of buildings:
abstract class BuildingBase<T> where T : BuildingTypeBase
{
public T Type;
}
abstract class BuildingTypeBase
{
}
class MiningBuildingType : BuildingTypeBase { }
class Building : BuildingBase<BuildingTypeBase>
{
}
class MiningBuilding : Building
{
public MiningBuilding()
{
Type = new MiningBuildingType();
}
}
public class Test
{
List<Building> buildings = new List<Building>();
void myCode()
{
var b = new MiningBuilding();
buildings.Add(b);
}
}
Yeah, sure. But like that I always have to cast "b" to $$anonymous$$iningBuilding to use its members. I was looking for a solution where I don't need to do that.
Just rethink everything and use components, ech single component can have own inheritance tree, whenever you wnat to find all buildings with some special buildingtype component, you will always be able to do it. What you need is to find out how to store persistent data and how to build your front-end with monobehaviours and components to consume these data. There can be also third layer, transferrable data format (in case you want to have some networking)
Thanks for your effort but that really doesn't help me. I've opened a Thread on StackOverflow and hope I'll find an answer on there. https://stackoverflow.com/questions/50215653/c-sharp-generic-class-inheritance-confusion
Your answer
Follow this Question
Related Questions
An OS design issue: File types associated with their appropriate programs 1 Answer
C# Inheriting from MonoBehaviour but still be able to instantiate with new()? How should I do this? 2 Answers
C# Generics not constraining correctly? 1 Answer
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers