Generics in C# using UnityEngine;

Facebook
Twitter
LinkedIn

Introduction

What if you need to create a class that can interact with a particular object type, such as an integer, or a class, but we don’t want to make x different classes, one for strings, one for integers, one for floats, etc. In this post I will be getting into generics in C# and how they are used and why they are used. Some of the places that generics are used for could possibly be for creating a base singleton class that can be used as a base class. We’ll be using this as an example.

What are Generics

Generics in C# are used to specify classes that you don’t know what they might be. For example in terms of game development you may have multiple singletons. A singleton skeleton is basically checking if another version instance exists, if it does, destroy ourselves, otherwise set the instance to ourselves. If you have 5 different singleton classes, that’s 5 different scripts that do the exact same thing. Generics are great for this. You’d create a base class named Singleton and each script can inherit from it. Because we use generics we can also specify the parent type. It’ll make more sense when seeing an example.

Examples

Generics are typically declared like this,

public class Example<T>
{
    public T genericVariable;
}

public class IntegerExample : Example<int>
{
    void DoSomething()
    {
        genericVariable ++;
    }
}

In this example were are declaring a class Example that takes in a generic type. The type used is then used as a type for a variable. Next we create a class, IntegerExample that inherits from Example and declares the generic as an integer. This allows us to then use the ‘genericVariable’ as an integer. If we instead used a List of integers we can then use genericVariable as a list of integers. Whatever we input as the generic type then that’s what we’ll use. You can declare as well explicit requirements for generics as well if you have a specific base.

public class Example where T : ExampleBase
{

    public T exampleBaseType;

    public void TellBaseToDoSomething()
    {
        exampleBaseType.DoSomething();
    }
}

public class ExampleBase
{
    public virtual void DoSomething()
    {

    }
}

public class ExampleBaseExtended : ExampleBase
{
    public override void DoSomething()
    {

    }
}

public class ExampleTest : Example<ExampleBaseExtended>
{
    void Test()
    {
        TellBaseToDoSomething();
    }
}

In this example we go a bit further and create our own classes. Here the objective is to access the ExampleBaseExtended from the Example class rather than the ExampleBase class. Generics make it easy and simple to create variables for types you don’t know the name of and for classes that inherit from the same parent.

Singleton Modules In Unity

I’d like to show a live example of how generics might be used and singleton’s seemed like the best example of this in Unity.

public class Module : MonoBehaviour where T: Component
{

    public static T instance
    {
        get
        {
            if(_instance == null)
            {
                Init();
            }

            return _instance;
        }
        set
        {
            _instance = value;
        }
    }
    private static T _instance;

    private static void Init()
    {
        GameObject holder = GameObject.Find("[Modules]");
        if(holder == null)
            holder = new GameObject("[Modules]");

        instance = holder.AddComponent();
    }
}

public class ModuleExample : Module<ModuleExample>
{
    public int example;    
}

public class ModuleExampleTest
{
    public Test()
    {
        ModuleExample.instance.example++;
    }
}

Let’s take a closer look into this. In our Module class we declare a generic type of type Component which is required for Unity’s AddComponent which inherits from MonoBehaviour. We then make a getter and setter for a static variable of the type. We then check if the instance exists, if it doesn’t we’ll create a new instance and set our _instance variable to it. If it does then return _instance. Other classes can simply extend from this and now have all the functionality as a regular singleton and it’s incredibly simplified and uses object oriented programming to it’s benefit to create a base skeleton that can be used by any other class.

Best Practices

It can be tricky to know when exactly you should use generic types. Typically I will ask myself, “Will this script/class ever be re-used and is it worth the effort to make”. Then depending on the situation I will go and try to make a script/class that can be used by anything that might ever need to use it and making it open enough to allow that. For example, I also use generic types for my file management system where it takes in a class and string then automatically either saves or loads that class using the string as its file name. So rather than code in a saving and loading methods for each class that might be saved/loaded, I simply use an abstract class to handle this for me.

As you use the language more and work on deeper mechanics for your games it becomes more intuitive and obvious when to use generics, but if you notice that you’re using the same exact skeleton for a class then its a good sign you need to abstract, whether it be polymorphism or generics in C#.

Conclusion

To conclude, generics are used rarely but when used they can be powerful. I have maybe 4 classes in 60+ classes in my project, The Multiplier, that use generics for their functionality. They have a specific purpose and when used correctly can save your project from becoming disorganized and spending time managing spaghetti.

I hope I helped any programmers who are struggling with understanding generics and how to use them effectively, leave any comments or suggestions on how I could improve this post.

More to explore

Designing an Educational Game

A blog post covering my experience designing an educational game for 5th grade students in the US following common core standards.