Reputation: 5094
I'm writing some components (this kind of component) for a small personal game project. In this system, entities have various types of components which belong to various categories. For example, the IController category of components includes KeyboardController and AiController. An entity has a collection of components, and should only have one component from each category. All components inherit from IComponent.
Components have a MetaType property which should report a type they correspond to, in order to say: "Hey, please treat me as this type of component!" This property returns a Type object. The AiController returns typeof(IController), telling the Entity to treat this as its controller. Other valid MetaTypes for it would be typeof(AiController) or typeof(IComponent). It should not be able to return any arbitrary type, e.g. typeof(int) - just component types.
Currently my components can report any arbitrary type for a MetaType. The AIController can actually return typeof(int), for instance - that's a valid Type object, after all.
Can I constrain the Type values such that the only valid types would be the type of any class or interface for which IComponent is an ancestor? I imagine such a variable declaration might look like this:
Type<IComponent> component; // This can only store certain types
Type where Type : IComponent component; // This too
I am specifically interested in whether this is possible - not so much in alternate approaches (I am aware of several, and they include just allowing this behaviour, since I'm the only one working with this code.
Upvotes: 3
Views: 1137
Reputation: 23208
You could create a MetaType
object whose constructors or factory methods would take a generic type constrained against IComponent
and provide access to the non-constrained Type
. But since its constructors are constrained, you should be guaranteed to not get other non-IComponents.
public class MetaType
{
public Type ComponentType { get; private set; }
private MetaType(Type componentType)
{
this.ComponentType = componentType;
}
public static MetaType Create<T>() where T : IComponent
{
return new MetaType(typeof(T));
}
}
Your usage might look like:
MetaType validType = MetaType.Create<IComponent>(); //fine
MetaType validType = MetaType.Create<IController>(); //fine
MetaType validType = MetaType.Create<AIController>(); //fine
MetaType invalidType = MetaType.Create<int>(); //compiler error!
EDIT: I'm assuming that your IController
interface inherits from IComponent
, but if it doesn't, you can add factory overloads like CreateController
and CreateComponent
each one constrained against the unique interface.
Upvotes: 4
Reputation: 410
Not directly, unfortunately - whilst you can constrain type parameters in generics, type variables like your MetaType
field can't be constrained. It's basically like trying to constrain an int
: you can use exceptions to make sure it's never set to an invalid value but ultimately the variable itself could be anything of the right type.
Upvotes: 1