# typeof and GetType() — a Type is its name

> typeof(X) and x.GetType() answer a Type, which is the type's name: Name ("Int32"), FullName ("System.Int32"), ToString() and ==. GetType() is the type the value IS at run time. Inside a generic class, typeof(T) and `x is T` read the type the instance was built over; a caught exception's GetType() is the type it was thrown as. The rest of reflection is not available yet.

<!-- id: types-type · area: types · stability: stable · html: https://osysharp.com/reference/types/type/ -->

## Summary        {#summary}
A `Type` names a type:

```osy title="typeof, GetType() and a generic class's own T" run app=types-type
class Shape { public string Label = ""; }
class Circle : Shape { }
class Square : Shape { }

class Bin<T> where T : Shape {
  public string Holds() => typeof(T).Name;
  public bool Fits(Shape s) => s is T;
}

[Test]
void A_Type_Is_Its_Name() {
  Assert.Equal("Int32", typeof(int).Name);
  Assert.Equal("System.String", typeof(string).FullName);
  Shape s = new Circle();
  Assert.Equal("Circle", s.GetType().Name);              // what it IS, not what it is held as
  Assert.True(s.GetType() == typeof(Circle));
  var bin = new Bin<Circle>();
  Assert.Equal("Circle", bin.Holds());
  Assert.True(bin.Fits(new Circle()));
  Assert.False(bin.Fits(new Square()));
}
```

## Signature      {#signature}
```osy syntax
typeof(X)          // a Type: Name, FullName, ToString(), ==
x.GetType()        // the type x is at run time
typeof(T) / x is T // inside a generic class: what this instance was built over
```

## Description    {#description}

### What can I ask a Type?   {#members}
Its `Name` (without namespace), its `FullName`, `ToString()` (the full name) and whether it is `==` another. A
built-in answers its .NET name (`int` is `System.Int32`). The rest of C#'s reflection — `GetProperties()`,
`IsClass`, `BaseType`, … — is not available yet and is a compile error that says so; read-only reflection over a type's
members is planned.

### What does GetType() answer for a value held as its base?   {#runtime}
The type it actually is — `Shape s = new Circle(); s.GetType()` is `Circle`. On a null value it throws
`NullReferenceException`, as in C#.

That holds across a package too: a kit's function that takes a `Worker` and is handed an instance of your app's
`class Robot : Worker` answers `Robot`, though the kit was written without ever seeing it. The class is read from
the value.

### What does a caught exception's GetType() answer?   {#exception}
The type it was thrown as, named as C# names it — the line every `catch` reaches for first:

```osy title="GetType() in a catch" run app=types-type-exception
class ParcelLostException : NotFoundException { }

string Why(int n) {
  try {
    if (n == 1) throw new InvalidOperationException("the parcel is sealed");
    throw new ParcelLostException("no parcel 7");
  } catch (Exception e) {
    Log.Warning(e.GetType().Name + ": " + e.Message);
    return e.GetType().Name;
  }
}

[Test]
void A_Caught_Exception_Knows_Its_Type() {
  Assert.Equal("InvalidOperationException", Why(1));
  Assert.Equal("ParcelLostException", Why(2));
  Assert.Equal("System.InvalidOperationException", typeof(InvalidOperationException).FullName);
  Assert.Equal("System.Collections.Generic.KeyNotFoundException", new KeyNotFoundException("k").GetType().FullName);
}
```

A .NET exception's `FullName` is its .NET one (`System.InvalidOperationException`, the base `System.Exception`), a
platform exception's is `Osysharp.NotFoundException`, and yours carries the namespace you declared it in. It is the
same on the server and in a component's `action`, and `e.GetType() == typeof(InvalidOperationException)` holds.

### How does a generic class know its T?   {#generic-class}
Each instance carries the types it was built over, set where it is created — so `typeof(T)` and `x is T` inside the
class's own members answer for THIS instance, including one created inside another generic class from that class's
own type parameter (`new Box<U>(item)` inside `Wrap<U>`). A `static` member has no instance, so there they are an error
that says to make the type the member's own type parameter.

### What is a generic class called?   {#generic-name}
What .NET calls it: its name with its arity — `Box`1` for `Box<T>`, whatever it was built over. `typeof` takes a
constructed or an open generic as C# does:

```osy title="a generic class's name" run app=types-type
class Box<T> { public T Value; public Box(T v) { Value = v; } }

[Test]
void A_Generic_Class_Is_Named_With_Its_Arity() {
  Assert.Equal("Box`1", new Box<int>(1).GetType().Name);
  Assert.Equal("Box`1", typeof(Box<string>).Name);
  Assert.Equal("Box`1", typeof(Box<>).Name);
}
```

## See also       {#see-also}
- [nameof](https://osysharp.com/reference/function/nameof/) — a name folded at compile time
- [Generic classes](https://osysharp.com/reference/class/generics/) — generic classes and methods
- [Testing which class a value is](https://osysharp.com/reference/class/type-tests/) — `is`, `as` and type patterns
