Generics are a feature whereby classes and methods,
amongst other things, can be passed a type as a parameter.
This, in effect, allows you to program generically without knowing
the exact type of the data you'll be working with.
We have seen before that the GetComponent() method
uses a generic parameter to get the type
of the component that it's looking for.
GetComponent() is what is known as a generic method.
Let's take a look at creating one.
Here we have an example of a simple generic method,
the first thing to look at is its generic parameter.
This is named "T", and is enclosed in angle brackets.
After the method's name, and before the normal, or formal parameters.
Since this T could represent any type, its name is arbitrary;
but most use the letter "T" by convention.
Similarly, if you wish to have multiple generic parameters,
you can use a comma to add more.
The naming convention usually follows
that parameters after "T" are "U", and then "V".
Though generic functions are not limited to only three parameters,
it is quite uncommon to see one with more than three.
We now know that the generic type associated with this method is "T".
T is only a placeholder though, and will end up being
an actual type when the method is called.
Whatever type T ends up being will also be the
return type and the argument type for the method
since both of those use T as their type.
Even though we have a method that works with a generic type,
it's currently not very useful.
So what can we do with a generic type?
Well since we don't know how this generic type will act,
we can't do much with it.
This generic parameter could be anything from a float,
to a MonoBehaviour, and more.
Since we don't know what it is, there aren't
many operations we can perform on it.
We cannot, for example, multiply our MonoBehaviour by two,
and we can't access the GameObject field of a float.
Right now it's just treated as though it were the class object,
which is the base class that all C# classes implicitly inherit from.
So how do we perform more operations?
In order to know some of the features of the type, we have to
limit what types it can be by placing a constraint
on the generic parameter.
To add constraints to our function, we type "where"
after the parameters, but before the function body.
This is followed by the generic type we're going to constrain,
in our case, "T", and then a colon.
After the colon, we have the specific constraints separated by commas,
The constraints generally fall into four categories.
You can use either the keyword "class"
to make sure T is a reference type,
or the keyword "struct" to make sure it's a value type.
You can use the keyword "new", followed by a pair of parentheses,
to ensure that it has a public constructor with no parameters.
You can use a class name to say that T is that class,
or via polymorphism, any class that derives from it.
The last category of constraints is interfaces.
You can use an interface name to say that T
has implemented that interface.
In order to use a generic method, you must specify
what type you want it to use.
Let's say you wanted to use the generic method you just created.
In another class you would write the name of the method
followed by angle brackets, then the type you want.
You would then follow that with the parenthesis and any arguments.
All features that we've discussed apply to generic classes
and interfaces, as well as methods.
By giving a class generic types, you can effect the types of fields,
properties, and methods within it.
Making generic classes is one of the more common uses of generics,
and makes it very easy to implement data structures.
Let's take a look at a generic class now.
This class uses a generic type of T.
This means that every instance of the type T
used as a type in the class, will be replaced by
an actual type when it is used.
This class has a single-member variable
named "item" that is of type T.
The class also has a method called UpdateItem()
that takes in a single argument of type T
and assigns it to the member "item".
In order to instantiate an object of this class,
you must specify a type for T.
You do this by typing the name of the class,
followed by angle brackets and the type you want.
You must also do this after typing the name of the constructor,
and before the constructor's parameter list.
One of the most common uses of generics is for
collections, like dictionaries and lists.
For more information on dictionaries and lists,
see the lesson linked below.