| Keywords | GetType(), typeof, is, as, (T) cast, nameof, var |
|---|---|
| Category | Type system |
| In Unity | RequireComponent(typeof(Rigidbody)), if (other is IDamageable d) |
Types & Type Checking
Sometimes you have a variable of a general type (Component, Enemy, object) and need to know what it actually is, or treat it as something more specific. C# gives you several tools: GetType(), typeof, is, as and casts.
A parcel labeled "Package". GetType() is reading the exact label inside: "Blue Ceramic Mug". is is asking "is this some kind of Mug?" (yes for a blue mug, a red mug or a travel mug). as is "open it as a mug; if it's not a mug, give me nothing". A cast is "this IS a mug, trust me", and if you're wrong, it throws an error.
Quick reference
| Tool | Returns | If the type doesn't match | Example |
|---|---|---|---|
obj.GetType() | The exact runtime Type | n/a | enemy.GetType().Name → "Goblin" |
typeof(T) | The Type for a class name you write | n/a | typeof(Rigidbody) |
obj is T | bool | false | if (enemy is Goblin) |
obj is T t | bool + a typed variable | false, t unusable | if (enemy is Goblin g) g.Taunt(); |
obj as T | T or null | null | Goblin g = enemy as Goblin; |
(T)obj | T | Throws InvalidCastException | Goblin g = (Goblin)enemy; |
nameof(x) | The name as a string | Compile error if it doesn't exist | Invoke(nameof(Respawn), 2f) |
GetType() vs typeof
Both give you a System.Type object that describes a type. The difference is when the type is known.
Enemy e = GetComponent<Enemy>(); // the variable's type is Enemy...
Debug.Log(e.GetType().Name); // ..."Goblin": GetType() asks the OBJECT at runtime
Debug.Log(typeof(Enemy).Name); // "Enemy": typeof() is decided when you write the code
// Exact type check (subclasses do NOT match)
if (e.GetType() == typeof(Goblin)) { }
// Where Unity wants a Type
[RequireComponent(typeof(Rigidbody))]
public class Hover : MonoBehaviour { }
Component c = gameObject.AddComponent(typeof(BoxCollider)); // non-generic version
e.GetType() == typeof(Enemy) is false for a Goblin, because it checks the exact type. e is Enemy is true for a Goblin, because a Goblin is a kind of Enemy. You almost always want is.is: check and convert in one step
void OnTriggerEnter(Collider other)
{
Component c = other.GetComponent<Enemy>();
// Pattern matching: if it's a Boss, give me a Boss variable called "boss"
if (c is Boss boss)
{
boss.StartPhaseTwo();
}
else if (c is Enemy enemy)
{
enemy.TakeDamage(10);
}
}
Modern C# also allows is not: if (target is not null). But for Unity objects, prefer != null; see the warning below.
switch on type
string Describe(Item item)
{
switch (item)
{
case Weapon w when w.damage > 50: return "A deadly weapon";
case Weapon w: return $"A weapon ({w.damage} dmg)";
case Potion p: return $"A potion that heals {p.healAmount}";
case null: return "Nothing";
default: return item.name;
}
}
Casting numbers
Casts also convert between number types. Going to a "smaller" type needs an explicit cast and can lose information.
float f = 3.9f;
int i = (int)f; // 3: casting cuts off the decimals (doesn't round)
int r = Mathf.RoundToInt(f); // 4: rounds properly
int hp = 37, max = 120;
float bad = hp / max; // 0: int / int is integer division, THEN converted
float good = (float)hp / max; // 0.308...
var
var lets the compiler figure out the type from the right-hand side. The variable still has a fixed type; you just don't write it.
var rb = GetComponent<Rigidbody>(); // rb is a Rigidbody
var enemies = new List<Enemy>(); // enemies is a List<Enemy>
// var x; // error: nothing to infer from
What happens at runtime
- Every object remembers its real type.
GetType()reads it;is,asand casts compare against it. typeofandnameofare resolved when the code compiles, so they cost nothing at runtime.is,asand casts are fast, butGetType()plus reflection (reading methods and fields by name throughType) is slow. Avoid reflection inUpdate.
Common Mistakes
is null/aswith destroyed Unity objects. These skip Unity's special null check, so a destroyed object still "is" a GameObject. Use== null/!= nullfor Unity objects. See Null & Nullable Types.asfollowed by no null check.(enemy as Boss).StartPhaseTwo()throwsNullReferenceExceptionfor non-bosses. Useif (enemy is Boss b).- Casting when you should use GetComponent. A
GameObjectis never aRigidbody;(Rigidbody)gameObjectdoesn't compile. Components are attached to GameObjects, not the same object. - Comparing type names as strings (
GetType().Name == "Goblin"). A rename breaks it silently. Useis Goblin.
See also
- Inheritance & Interfaces
- Generics (
GetComponent<T>) - Attributes (reading attributes with reflection)
This page is a simplified, AI-assisted interpretation. For the complete and authoritative reference, see the official Microsoft C# documentation.