Why is 0 a type in Microsoft Intermediate Language MSIL?
Master System Design with Codemia
Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.
Introduction
The title is a little misleading: the interesting IL syntax is not 0, but !0. In MSIL, !0 is not the integer zero pretending to be a type. It is notation for "the first generic type parameter" in the current generic type definition.
What !0 Means
In IL, generic parameters are often written by index rather than by their source-language names. So if you define a generic type such as Box<T>, the type parameter T may appear in IL as !0.
The pieces mean:
- '
!means "generic parameter of a type"' - '
0means "the first one"'
So:
- '
!0means the first generic type parameter of the enclosing type' - '
!1means the second generic type parameter of the enclosing type'
This is an indexing scheme, not a literal zero-valued type.
A Simple Example
Consider this C# code:
In IL, the field type is expressed in terms of the generic parameter slot:
The field is typed as !0, which means "whatever concrete type gets substituted for the first generic parameter when this generic type is constructed."
!0 Versus !!0
IL uses two related notations:
- '
!0for a generic parameter of the enclosing type' - '
!!0for a generic parameter of the current method'
That distinction matters when both the type and the method are generic.
Here is a conceptual example:
In IL terms:
- '
Tmaps to!0' - '
Umaps to!!0'
The single exclamation and double exclamation are not decoration. They identify two different generic-parameter scopes.
Why IL Uses Indexes Instead of Names
Source languages care about readable names such as TKey, TValue, or TResult. IL cares more about metadata structure. The runtime does not need the source-language parameter names in order to track the generic slots correctly. Index-based notation is compact and unambiguous at the IL level.
That is why !0 looks odd if you come from C#, but it is perfectly natural from a metadata perspective.
Another Example with Two Type Parameters
Suppose you define:
The IL-style interpretation is:
- '
TFirstbecomes!0' - '
TSecondbecomes!1'
So the fields conceptually look like:
Again, the numbers are just zero-based indexes into the generic parameter list.
Why It Is Called a Type
You may wonder why !0 is described as a type at all. The answer is that a generic parameter is a valid type variable in the CLR type system. Even though it is not a concrete runtime type like System.Int32, it still behaves as a type placeholder that can be used in:
- field declarations
- method signatures
- local variable types
- constraints
- return types
So !0 is a type parameter slot, and the CLR treats that slot as part of the type system.
Where You Usually See It
Most developers only encounter !0 when:
- reading disassembled IL
- inspecting metadata in tools such as ILDasm
- debugging generic signatures in emitted assemblies
- working with Reflection or code generation
You normally do not write this notation in C# or VB.NET because the compiler hides it behind generic parameter names.
Common Pitfalls
One common mistake is reading !0 as the number zero or as some special builtin CLR type. It is neither. It is the first generic type parameter slot.
Another issue is forgetting the distinction between !0 and !!0. The first refers to a generic type parameter, while the second refers to a generic method parameter.
Developers also sometimes assume the numeric suffix is one-based. It is zero-based, so the first generic slot is 0, not 1.
Finally, if you are reverse-engineering IL, remember that source-language names such as T and U may not appear in the places you expect. Indexed notation is normal at that level.
Summary
- The meaningful IL notation is
!0, not plain0. - '
!0means the first generic type parameter of the enclosing generic type.' - '
!!0means the first generic type parameter of the current generic method.' - The numeric part is a zero-based generic-parameter index.
- '
!0is treated as a type placeholder in CLR metadata, which is why it can appear in signatures and field declarations.'

