fixed 陳述式 (C# 參考)

fixed 陳述式可防止記憶體回收行程重新配置可移動的變數。 fixed 陳述式只能用於不安全的內容中。 您也可以使用 fixed 關鍵字來建立大小固定的緩衝區

fixed 陳述式會將指標設定為 Managed 變數,並在陳述式執行期間「固定」該變數。 可移動之受控變數的指標只適用於 fixed 內容。 如果未使用 fixed 內容,記憶體回收可能會意外地重新配置變數。 C# 編譯器只能讓您將指標指派給 fixed 陳述式中的 Managed 變數。

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

您可以使用陣列、字串、固定大小緩衝區或變數位址,來初始化指標。 下列範例說明如何使用變數位址、陣列和字串:

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

從 C# 7.3 開始,fixed 陳述式對陣列、字串、固定大小緩衝區或 unmanaged 變數以外的其它型別都可運作。 針對名稱為 GetPinnableReference 的方法,可以將任何實作方法的型別加以固定。 GetPinnableReference 必須傳回 unmanaged 型別ref 變數。 .NET Core 2.0 中引入的 .NET 型別 System.Span<T>System.ReadOnlySpan<T> 使用此模式,而且可以加以固定。 下列範例會顯示這一點:

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

如果您正在建立應該參與此模式的型別,請參閱 Span<T>.GetPinnableReference() 以取得實作模式的範例。

如果指標的型別全都相同,則可以在一個陳述式中初始化多個指標:

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

若要初始化不同類型的指標,只要巢狀 fixed 陳述式即可,如下列範例所示。

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

執行陳述式中的程式碼之後,任何固定的變數都會取消固定並受限於記憶體回收。 因此,請不要指向 fixed 陳述式之外的變數。 fixed 陳述式中所宣告變數的範圍會設為該陳述式,使其更加簡單:

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

fixed 陳述式中初始化的指標是唯讀變數。 如果您要修改指標值,則必須宣告第二個指標變數並予以修改。 在 fixed 陳述式中宣告的變數無法修改:

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

您可以配置堆疊上的記憶體,此處不受記憶體回收限制,因此不需要釘選。 若要這樣做,請使用 stackalloc 運算式

C# 語言規格

如需詳細資訊,請參閱 C# 語言規格fixed 陳述式一節。

另請參閱