The fixed
statement prevents the garbage collector from relocating a movable variable. The fixed
statement is only permitted in an unsafe
context.
You can also use the fixed
keyword to create fixed-size buffers as shown below.
unsafe struct MyStructure
{
public fixed int myFixedField[10];
}
Before C# 7.3, we used the fixed
statement to set a managed variable to a pointer and pins that variable during the execution of the statement.
Let's consider the following example in which we have created two variables of type MyStructure
. The numbers
variable contains values from 0 to 9 and the cubes
variable contains their cube values.
MyStructure numbers = new MyStructure();
MyStructure cubes = new MyStructure();
public unsafe void PrintArrayUsingPinning()
{
for (int i = 0; i < 10; i++)
{
fixed (int* ptrNumbers = numbers.myFixedField)
fixed (int* ptrCubes = cubes.myFixedField)
{
ptrNumbers[i] = i;
ptrCubes[i] = i * i * i;
}
}
for (int i = 0; i < 10; i++)
{
fixed (int* ptrNumbers = numbers.myFixedField)
fixed (int* ptrCubes = cubes.myFixedField)
{
Console.WriteLine(ptrNumbers[i] + " cube " + ptrCubes[i]);
}
}
}
Pointers to movable managed variables are useful only in a fixed
context. Without a fixed
context, garbage collection could relocate the variables unpredictably. The C# compiler only lets you assign a pointer to a managed variable in a fixed
statement.
fixed
field and save it into a pointer.fixed
statement body, you can use the pointer to make changes to the particular variable.Now in C# 7.3, this new feature allows you to index fixed fields without doing any pinning.
public unsafe void PrintArrayWithoutPinning()
{
for (int i = 0; i < 10; i++)
{
numbers.myFixedField[i] = i;
cubes.myFixedField[i] = i * i * i;
}
for (int i = 0; i < 10; i++)
{
Console.WriteLine(numbers.myFixedField[i] + " cube " + cubes.myFixedField[i]);
}
}
As you can see that we do not need to use the fixed
statement anymore to access those fields.