Generics is the concept of generalising types of objects in their class and method. It can be thought of as a variable for type. The types of generics are generalised until a class or method is declared. A generic class can be used to create a code pattern that can support multiple object types.
Generics can be created by adding
<T> after the class name. Here,
T is the generic type that gets set while calling it. A class can have multiple generic types that can be added by separating them with commas as
<T,U,V> . The general naming convention for creating generic types starts from T and moves alphabetically as T, U, V, etc.
This class has the
GetMyType method that simply returns the type of generic class. A generic class is not very useful as the type
T can be anything. To use
T , we can limit its type.
Constraint on Generic Type
A constraint limits the generic type, which allows us to use more properties of generic types. A constraint can be given to a generic type by using the
Let's create a constraint for
MyGenericClass. We will create its constraint as
Monobehaviour. This limits the value of
MonoBehaviour or it's child class. This allows the use of
MonoBehaviour 's properties.
Using Generics with Inheritance
We will be creating an inventory system to handle consumable and non-consumable items for our demonstration.
Let us first create a base class
Item . It will contain properties
ownedQuantity . This will contain two public methods,
PurchaseItem . A virtual method
Use will be used to consume the item. This method will be handled separately from the child classes.
Let's create two child classes deriving from the
Item base class. Both will have different constructors. Also, they both will override the
Use method separately. The
ConsumableItem class will decrease owned items by 1 when used.
To further differentiate the two classes, let's also add
UnEquip method to
Now that we have the required base classes, we will be creating a controller class for them. We will use a generic system to make a controller.
Let's create a class
ItemClass that has the generic type
T . The type
T will be limited to
Item class so that we can use the properties of the
Item class. In this class, create a list of type
T so that items can be stored.
List is also a generic class, so we can pass
T as a type. Now, we create the methods
AddItem to add inventory items,
GetItem to get items from the name and
UseItem to use items with the name.
Now to demonstrate its use, let's create a
Demo class with
CreateInventory method. This method will create a controller, add items, and use the item.
At first, create two controllers
nonConsumableItemController for handling
NonConsumable item by passing them as a generic type. Now, add items to them using the
AddItem method. Note that only items of defined generic type while creating a controller can be added.
Added items can be used by calling the
ItemController.Use(string) method. Also, try
GetItem using the
ItemCOntroller.GetItem(string) method. This will always return the defined generic type for the controller.
Characteristics of a Generic System
- A generic class can be used as a template for code. It can make a block of code reusable. In the above
UseItemmethods were reused for both
NonConsumableclasses. This generalisation makes modification easier as only the generic class needs to be modified. However, this should be used in moderation, as using it too much will make it harder to maintain.
- Generic classes are type-safe. Once a generic class is defined with a type, its type cannot be changed. This can be seen in the example above when we created the
consumableItemControlleris created using
ConsumableItemas the generic type, so it is expecting an object of the same type when calling
AddItemand returning an object of the same type when calling
- Type check is done at compile time. This lets us find issues when compiling rather than finding issues during runtime. Fixing issues during compiling is easier than during the runtime.
- Strong type checking is used in a generic system. Once an object is created with a type, even its parent class cannot be used instead of the object.
Let us consider a snippet from the above example,
consumableItemsControllerwas created using
AddItemonly accepts an object of type
The following line gives the compile-time error,
This is because strong type checking is done.
Itemis not accepted even if it is the base class for
ConsumableItem. This eliminates casting as we will always receive items of provided generic type.
- Generics are more efficient as it removes the need for boxing, unboxing and casting objects.
Using generic systems, re-usable code can be written that can be easily maintained. I hope this blog helps you implement a generic system in your system.
Thank you for reading!