However, I see no reason why you need the constraints in the first place. Do you really need to ensure that a `Unit` only contains one type of `Creature`? Do you _really_ need to use inheritance and derived classes to define different creatures rather than using data and member variables on a single type (do they - from a functional/computational standpoint - differ in behavior)?
Your problems will be solved by abandoning generics for this use case (it's not an appropriate or meaningful use of generics) and using data-driven design and component-based design.
In the game, a unit is a collection of a specific type of creatures. So, I could have a unit of 25 archers, a unit of 40 swordsmen, a unit of 10 peasants, etc. I don't want to be able to mix and match creature types in a unit, so a unit shouldn't have 15 archers and 10 peasants. An army is a collection of units, so if you want to mix and match creatures, you create various unit types and add them to the army (one unit of 15 archers, another unit of 10 peasants).
The bolded portion is a really good question and point for me to ponder. It's certainly something worth keeping in mind when contemplating whether to create inherited classes.
In the code I posted above, the creature types were more for illustration of concept than for usage in practice.
In my actual game though, the player wizard is an object which derives from the creature class. The player wizard can do all sorts of things which a standard creature doesn't do (like channel mana and cast spells) and has a whole bunch of attributes which no other creature needs to worry about (age, ghost state, etc). So, it would make sense for the wizard to be a derived class from Creature. If I were to add a simple peasant, it wouldn't need a distinct class and could just be an instance of Creature with its specific distinctions being set in the Creature properties. Who knows what other creatures and special rule sets I'll need? Whatever it eventually becomes, the architecture should be robust enough to support it with as little change to code as possible.
If this is what you want...
- Unit to only contain one specific type of Creature.
- Armies to contain Units, where different Units can have different Creatures.
...then this is what I would do:
- Make a base "Unit" class which is not generic.
- Make a "Unit<T>" class which derives from Unit.
- Have Army contain a List<Unit> instead of List<Unit<T>>.
NOTE: You can still break a Unit's single-type nature by adding creatures of a more derived type than T. It only prevents you from adding Creatures of a more basic type. If your Creature hierarchy is entirely abstract and sealed classes, then this will work fine.
Instead of using generics, you can enforce a specific, single Creature type in a different manner:
- Remove the generic T from the Unit completely (same as first suggestion).
- Give the Unit a "public readonly Type Type;" member which is set by the constructor.
- Change the Unit's List to List<Creature> (same as the first suggestion).
- Make your Unit's Add method only allow the exact type you specified in the ctor: (item.GetType() == Type)
- Make sure you cannot bypass the Add method (you can make Unit implement IList and restrict access to the internal collection - personally I would write my own collection separate from Unit if this kind of type safety was a major concern).
Lastly, if you don't actually care about having a single-Creature-type Unit restriction, then just remove the generics from your own classes and methods entirely:
- Unit.critters : List<Creature>
- Army.units : List<Unit>
Thank you! This is exactly what I was looking for. I tested both of these and they both work.
I wanted to comment about an advantageous distinction between the first technique using generics vs. the second technique you describe where the type is used to filter out creatures...
Generics are a bit more visually messy and it's nice to be able to be avoid them if possible. That makes the second option you provide very attractive. There's a problem with that though: What if I want to spawn a bunch of creatures of some given type? (this is where my ignorance on C# language features may show up)
In a spawn method, I want to say, "Spawn X number of creatures of Type Y"
If I'm just given a class type, I don't know how to instantiate an object of that type. Here's my stab at a quick implementation of option #2:
public class Unit2
{
public readonly Type m_type;
List<Creature> critters = new List<Creature>();
public Unit2(Type type)
{
m_type = type;
}
public void Spawn(int count)
{
for (int a = 0; a < count; a++)
{
Creature c = new Creature();
object newCreatureType = Convert.ChangeType(c, m_type); //<-- Error: Object must implement IConvertible.
critters.Add((Creature)newCreatureType);
}
}
public void Add(Creature creature)
{
if (creature.GetType() != m_type)
{
Console.Write("Error: unit is not of right type!");
}
else
{
critters.Add(creature);
}
}
}
I really don't want to implement an IConvertible interface.
Implementing generics seems a lot easier (see below). The class type of the creature is included in the unit at run time, so I can instantiate an object of type T and it will be a creature of some derived class (goblin, troll, etc), and I don't have to know or care about what derived class it is.
public abstract class Unit
{
public virtual void print()
{
}
}
public class Unit<T> : Unit where T : Creature, new()
{
List<T> critters = new List<T>();
public void Add(T item)
{
critters.Add(item);
}
public void Spawn(int count)
{
for (int a = 0; a < count; a++)
{
T creature = new T();
critters.Add(creature);
}
}
public override void print()
{
foreach (Creature c in critters)
{
c.print();
}
}
}