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 impliesstruct
, 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