0

I know many programming and scripting languages, but I never saw something like this before:

camera = GetComponentInParent<Camera>();

Is this normal in C#? Why don't we have to pass the parameter Camera like this:

camera = GetComponentInParent(Camera);

Where can I inform myself about why it is like this?

Manfred Radlwimmer
  • 13,257
  • 13
  • 53
  • 62
Black
  • 18,150
  • 39
  • 158
  • 271
  • Unity also has a (very) short introduction to generics: https://docs.unity3d.com/Manual/GenericFunctions.html – UnholySheep Oct 24 '17 at 10:18
  • 1
    Btw, the non-generic equivalent of the first call is [`GetComponentInParent(typeof(Camera));`](https://docs.unity3d.com/ScriptReference/Component.GetComponentInParent.html) – Manfred Radlwimmer Oct 24 '17 at 10:22
  • Ok thanks, I did not know that this is called "generics" so I did not know what to even search for. – Black Oct 24 '17 at 10:28

2 Answers2

3

The parameter in the first version is a type parameter. Type parameters do not refer to values, but to types. This is used in generic methods and classes, that allow (a certain) flexibility of the types used in the class, while staying statically typed.

Compare the generic list class List<T>. You have to pass a type parameter to enforce that you can't add instances of other types.

List<int> myList = new List<int>();

myList.Add(1);
myList.Add(2);

foreach(var item in myList)
{
    // ...
}

Since myList has the type parameter int you and the compiler (and intellisense) know, that everything in myList is an int. Hence item will have the type int. On the other hand the following is not possible

myList.Add("FooBar");

since List<T>.Add has the signature void Add(T item) and creating a List<int> fixes the typeparameter T to int.

The second syntax

If Camera is a type this syntax is no valid C#. The compiler will throw the error

Camera is a type, which is not valid in the current context.

If GetComponentInParent would take a Type parameter (a parameter of the type Type, not a generic type parameter) you could call it like

GetComponentInParent(typeof(Camera))

but you will lose the merits of generics, i.e. the return type of GetComponentInParent won't be a Camera, but a less specialized type. If the components that can be returned by GetComponentInParent have no common ancestor, it might even return an object, whereas the generic version might have the signature

T GetComponentInParent<T>()

ich which case it would return the right type out of the box without the need to cast the result.

Paul Kertscher
  • 9,416
  • 5
  • 32
  • 57
2

The argument inside the angle brackets is a type argument used for what is called "generics". The GetComponentsInParent method uses the C# generics functionality to have a different return type based on the generic type argument. You likely use this concept often without thinking too much about it when you are using lists. If I have a list of Camera objects, the way that I will create it is to say var cameras = new List<Camera>(); as opposed to var cameras = new List(Camera);.

The GetComponentsInParent method has a signature of T[] GetComponentsInParent<T>(). If is was to take a type in the parameter list instead of using generics, the signature would have to be object[] GetComponentsInParent(type T) or may GameObject[] GetComponentsInParent(type T) and it would be your code's responsibility to cast the returned array elements into the object that you actually need. Generics help us make these scenarios much cleaner.

For more information on generic types in C#, see https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/generics/

Kyle Burns
  • 1,164
  • 7
  • 16