fixed – příkaz (Referenční dokumentace jazyka C#)

Příkaz fixed zabrání systému uvolňování paměti v přemístění vyměnitelné proměnné. Příkaz fixed je povolen pouze v nezabezpečeném kontextu. Klíčové slovo můžete použít také fixed k vytvoření vyrovnávacích pamětí s pevnou velikostí.

Příkaz fixed nastaví ukazatel na spravovanou proměnnou a přisoudí ji během provádění příkazu. Ukazatele na pohyblivé spravované proměnné jsou užitečné pouze v fixed kontextu. Bez kontextu fixed by uvolňování paměti mohlo proměnné nepředvídatelně přemístit. Kompilátor jazyka C# umožňuje přiřadit ukazatel na spravovanou proměnnou pouze v fixed příkazu .

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;
    }
}

Ukazatel můžete inicializovat pomocí pole, řetězce, vyrovnávací paměti s pevnou velikostí nebo adresy proměnné. Následující příklad znázorňuje použití adres proměnných, polí a řetězců:

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]) { /*...*/ }

Počínaje jazykem C# 7.3 funguje příkaz na dalších typech kromě polí, řetězců, vyrovnávacích pamětí s pevnou velikostí nebo fixed nespravovaných proměnných. Jakýkoli typ, který implementuje metodu s GetPinnableReference názvem , lze připnout. Musí GetPinnableReference vracet ref proměnnou nespravovaného typu. Typy .NET System.Span<T> a System.ReadOnlySpan<T> představené v .NET Core 2.0 tento vzor používají a lze je připnout. To je znázorněno v následujícím příkladu:

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);
    }
}

Pokud vytváříte typy, které by měly být součástí tohoto modelu, podívejte se na Span<T>.GetPinnableReference() příklad implementace vzoru.

V jednom příkazu lze inicializovat více ukazatelů, pokud jsou všechny stejného typu:

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

Chcete-li inicializovat ukazatele různých typů, jednoduše vnořte fixed příkazy, jak je znázorněno v následujícím příkladu.

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

Po spuštění kódu v příkazu se odepnou všechny připnuté proměnné a budou podléhat uvolňování paměti. Proto na tyto proměnné neukašete fixed mimo příkaz . Proměnné deklarované v fixed příkazu jsou vymezeny na tento příkaz, což usnadňuje:

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

Ukazatele inicializované v fixed příkazy jsou proměnné jen pro čtení. Pokud chcete upravit hodnotu ukazatele, musíte deklarovat druhou proměnnou ukazatele a upravit ji. Proměnnou deklarovanou v fixed příkazu nelze upravit:

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.
}

Paměť můžete přidělit do zásobníku, kde není předmětem uvolňování paměti, a proto není nutné ji připnout. K tomu použijte stackalloc výraz.

specifikace jazyka C#

Další informace najdete v oddílu s pevným příkazem specifikace jazyka C#.

Viz také