Sobes.tech
Senior

How do generics work at a low level in C#?

sobes.tech AI

Answer from AI

At the CLR (Common Language Runtime) level, generics are processed as follows:

  1. JIT Compilation: When a generic class or method is used with a specific type for the first time, the JIT compiler creates a specialized version of that code for the given type. For reference types (classes), a single shared version is created that uses the System.Object type to store elements, and casting occurs each time an element is accessed. For value types (structs), a separate, fully specialized version of the code is created for each unique type.
  2. Memory savings for reference types: Since the same JIT-compiled version of the code is used for all reference types, this saves memory compared to creating a new version for each reference type. However, there are overheads due to casting when accessing elements.
  3. Performance savings for value types: For value types, the JIT compiler creates a separate version for each type. This avoids boxing and unboxing and the associated overheads, thus improving performance.

Example of the difference in code generated for reference and value types:

// Generic class
public class MyGeneric<T>
{
    private T item;

    public T GetItem()
    {
        return item;
    }

    public void SetItem(T value)
    {
        item = value;
    }
}

// Usage with a reference type (string)
// JIT will create one version using System.Object
MyGeneric<string> stringGeneric = new MyGeneric<string>();

// Usage with a value type (int)
// JIT will create a separate, specialized version for int
MyGeneric<int> intGeneric = new MyGeneric<int>();

Thus, at a low level, generics in C# provide static typing and safety, while the CLR manages code generation in a way that optimizes performance and memory usage depending on the types used.