fixed, instruction (référence C#)fixed Statement (C# Reference)

L’instruction fixed empêche le récupérateur de mémoire de déplacer une variable mobile.The fixed statement prevents the garbage collector from relocating a movable variable. L’instruction fixed est uniquement autorisée dans un contexte unsafe.The fixed statement is only permitted in an unsafe context. fixed peut également être utilisé pour créer des mémoires tampons de taille fixe.fixed can also be used to create fixed size buffers.

L’instruction fixed définit un pointeur vers une variable managée et épingle cette variable pendant l’exécution de l’instruction.The fixed statement sets a pointer to a managed variable and "pins" that variable during the execution of the statement. Les pointeurs vers des variables managées ne sont utiles que dans un contexte fixed.Pointers to movable managed variables are useful only in a fixed context. Sans contexte fixed, le garbage collection peut déplacer les variables de manière imprévisible.Without a fixed context, garbage collection could relocate the variables unpredictably. Le compilateur C# permet seulement d’assigner un pointeur à une variable managée dans une instruction fixed.The C# compiler only lets you assign a pointer to a managed variable in a fixed statement.

class Point 
{ 
    public int x;
    public int y; 
}

unsafe private static void ModifyFixedStorage()
{
    // Variable pt is a managed variable, subject to garbage collection.
    Point pt = new Point();

    // Using fixed allows the address of pt members to be taken,
    // and "pins" pt so that it is not relocated.

    fixed (int* p = &pt.x)
    {
        *p = 1;
    }
}

Vous pouvez initialiser un pointeur à l’aide d’un tableau, d’une chaîne, d’un tampon de taille fixe ou de l’adresse d’une variable.You can initialize a pointer by using an array, a string, a fixed-size buffer, or the address of a variable. L’exemple suivant montre l’utilisation des adresses de variables, des tableaux et des chaînes.The following example illustrates the use of variable addresses, arrays, and strings. Pour plus d’informations sur les mémoires tampons de taille fixe, consultez Mémoires tampons de taille fixe.For more information about fixed-size buffers, see Fixed Size Buffers.

Point point = new Point();
double[] arr = { 0, 1.5, 2.3, 3.4, 4.0, 5.9 };
string str = "Hello World";

// The following two assignments are equivalent. Each assigns the address
// of the first element in array arr to pointer p.

// You can initialize a pointer by using an array.
fixed (double* p = arr) { /*...*/ }

// You can initialize a pointer by using the address of a variable. 
fixed (double* p = &arr[0]) { /*...*/ }

// The following assignment initializes p by using a string.
fixed (char* p = str) { /*...*/ }

// The following assignment is not valid, because str[0] is a char, 
// which is a value, not a variable.
//fixed (char* p = &str[0]) { /*...*/ } 

À compter de C# 7.3, l’instruction fixed s’applique à d’autres types au-delà des tableaux, chaînes, mémoires tampons de taille fixe ou variables non managées.Starting with C# 7.3, the fixed statement operates on additional types beyond arrays, strings, fixed-size buffers, or unmanaged variables. Tout type qui implémente une méthode nommée GetPinnableReference peut être épinglé.Any type that implements a method named GetPinnableReference can be pinned. GetPinnableReference doit retourner une variable ref d’un type non géré.The GetPinnableReference must return a ref variable to an unmanaged type. Consultez la rubrique consacrée aux types pointeur pour plus d’informations.See the topic on pointer types for more information. Les types .NET System.Span<T> et System.ReadOnlySpan<T> introduits dans .NET Core 2.0 utilisent ce modèle et peuvent être épinglés.The .NET types System.Span<T> and System.ReadOnlySpan<T> introduced in .NET Core 2.0 make use of this pattern and can be pinned. Ceci est illustré dans l'exemple suivant :This is shown in the following example:

unsafe private static void FixedSpanExample()
{
    int[] PascalsTriangle = {
                  1,
                1,  1,
              1,  2,  1,
            1,  3,  3,  1,
          1,  4,  6,  4,  1,
        1,  5,  10, 10, 5,  1
    };

    Span<int> RowFive = new Span<int>(PascalsTriangle, 10, 5);

    fixed (int* ptrToRow = RowFive)
    {
        // Sum the numbers 1,4,6,4,1
        var sum = 0;
        for (int i = 0; i < RowFive.Length; i++)
        {
            sum += *(ptrToRow + i);
        }
        Console.WriteLine(sum);
    }
}

Si vous créez des types qui doivent être inclus dans ce modèle, consultez Span<T>.GetPinnableReference() pour obtenir un exemple d’implémentation du modèle.If you are creating types that should participate in this pattern, see Span<T>.GetPinnableReference() for an example of implementing the pattern.

Plusieurs pointeurs peuvent être initialisés dans une instruction s’ils sont tous du même type :Multiple pointers can be initialized in one statement if they are all the same type:

fixed (byte* ps = srcarray, pd = dstarray) {...}

Pour initialiser des pointeurs de types différents, imbriquez des instructions fixed, comme indiqué dans l’exemple suivant.To initialize pointers of different types, simply nest fixed statements, as shown in the following example.

fixed (int* p1 = &point.x)
{
    fixed (double* p2 = &arr[5])
    {
        // Do something with p1 and p2.
    }
}

Une fois que le code de l’instruction est exécuté, toutes les variables épinglées sont libérées et soumises au garbage collection.After the code in the statement is executed, any pinned variables are unpinned and subject to garbage collection. Par conséquent, ne pointez pas vers ces variables en dehors de l’instruction fixed.Therefore, do not point to those variables outside the fixed statement. La portée des variables déclarées dans l’instruction fixed est limitée à cette instruction, ce qui facilite les choses :The variables declared in the fixed statement are scoped to that statement, making this easier:

fixed (byte* ps = srcarray, pd = dstarray)
{
   ...
}
// ps and pd are no longer in scope here.

Les pointeurs initialisés dans des instructions fixed sont des variables en lecture seule.Pointers initialized in fixed statements are readonly variables. Pour modifier la valeur du pointeur, vous devez déclarer une deuxième variable de pointeur et la modifier.If you want to modify the pointer value, you must declare a second pointer variable, and modify that. La variable déclarée dans l’instruction fixed ne peut pas être modifiée :The variable declared in the fixed statement cannot be modified:

fixed (byte* ps = srcarray, pd = dstarray)
{
    byte* pSourceCopy = ps;
    pSourceCopy++; // point to the next element.
    ps++; // invalid: cannot modify ps, as it is declared in the fixed statement.
}

En mode unsafe, vous pouvez allouer de la mémoire sur la pile, où elle n’est pas soumise au garbage collection et n’a donc pas besoin d’être épinglée.In unsafe mode, you can allocate memory on the stack, where it is not subject to garbage collection and therefore does not need to be pinned. Pour plus d’informations, consultez stackalloc.For more information, see stackalloc.

// Unsafe method: takes a pointer to an int.
unsafe static void SquarePtrParam(int* p)
{
    *p *= *p;
}

unsafe static void SquarePointValue()
{
    Point pt = new Point
    {
        x = 5,
        y = 6
    };
    // Pin pt in place:
    fixed (int* p = &pt.x)
    {
        SquarePtrParam(p);
    }
    // pt now unpinned.
    Console.WriteLine("{0} {1}", pt.x, pt.y);
    /*
    Output:
    25 6
     */
}

Spécification du langage C#C# Language Specification

Pour plus d'informations, voir la spécification du langage C#.For more information, see the C# Language Specification. La spécification du langage est la source de référence pour la syntaxe C# et son utilisation.The language specification is the definitive source for C# syntax and usage.

Voir aussiSee Also