Skip to content

Unmanaged generic type constraints C# 7.3performance

Constrain generic types to unmanaged types only.

C# generic constraints allowed specifying that a type parameter must be a struct, but this included both managed structs (containing references) and unmanaged structs (containing only primitive types). There was no way to restrict generic types to only unmanaged types.

C# 7.3 introduces the unmanaged constraint, which restricts a generic type parameter to unmanaged types only. This enables safe use of pointers, stack allocation, and interop scenarios with generic code.

Code

C#
public unsafe void ProcessBuffer<T>(T* buffer, int length) where T : unmanaged
{
    for (int i = 0; i < length; i++)
    {
        buffer[i] = default;
    }
}

public Span<T> AllocateOnStack<T>(int count) where T : unmanaged
{
    return stackalloc T[count];
}

// Usage
int* intBuffer = stackalloc int[10];
ProcessBuffer(intBuffer, 10); // Works with int

Point* points = stackalloc Point[5];
ProcessBuffer(points, 5); // Works with unmanaged structs
C#
// No way to write truly generic unmanaged code
public unsafe void ProcessIntBuffer(int* buffer, int length)
{
    for (int i = 0; i < length; i++)
    {
        buffer[i] = default;
    }
}

public unsafe void ProcessPointBuffer(Point* buffer, int length)
{
    for (int i = 0; i < length; i++)
    {
        buffer[i] = default;
    }
}

// Had to write separate methods for each type

Notes

  • Unmanaged types include primitives, enums, pointers, and structs containing only unmanaged types
  • The unmanaged constraint implies struct, so you don't need both
  • Unmanaged types cannot contain references, including string, arrays, or reference type fields
  • This constraint enables high-performance generic code with direct memory manipulation
  • Commonly used with Span<T>, stackalloc, and interop scenarios

More information