fixed 陳述式 (C# 參考)fixed Statement (C# Reference)

fixed 陳述式可防止記憶體回收行程重新配置可移動的變數。The fixed statement prevents the garbage collector from relocating a movable variable. fixed 陳述式只能用於不安全的內容中。The fixed statement is only permitted in an unsafe context. 您也可以使用 fixed 關鍵字來建立大小固定的緩衝區You can also use the fixed keyword to create fixed size buffers.

fixed 陳述式會將指標設定為 Managed 變數,並在陳述式執行期間「固定」該變數。The fixed statement sets a pointer to a managed variable and "pins" that variable during the execution of the statement. 可移動之受控變數的指標只適用於 fixed 內容。Pointers to movable managed variables are useful only in a fixed context. 如果未使用 fixed 內容,記憶體回收可能會意外地重新配置變數。Without a fixed context, garbage collection could relocate the variables unpredictably. C# 編譯器只能讓您將指標指派給 fixed 陳述式中的 Managed 變數。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;
    }
}

您可以使用陣列、字串、固定大小緩衝區或變數位址,來初始化指標。You can initialize a pointer by using an array, a string, a fixed-size buffer, or the address of a variable. 下列範例說明如何使用變數位址、陣列和字串:The following example illustrates the use of variable addresses, arrays, and strings:

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 變數以外的其它型別都可運作。Starting with C# 7.3, the fixed statement operates on additional types beyond arrays, strings, fixed size buffers, or unmanaged variables. 針對名稱為 GetPinnableReference 的方法,可以將任何實作方法的型別加以固定。Any type that implements a method named GetPinnableReference can be pinned. GetPinnableReference 必須傳回 unmanaged 型別ref 變數。The GetPinnableReference must return a ref variable of an unmanaged type. .NET Core 2.0 中引入的 .NET 型別 System.Span<T>System.ReadOnlySpan<T> 使用此模式,而且可以加以固定。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. 下列範例會顯示這一點: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);
    }
}

如果您正在建立應該參與此模式的型別,請參閱 Span<T>.GetPinnableReference() 以取得實作模式的範例。If you are creating types that should participate in this pattern, see Span<T>.GetPinnableReference() for an example of implementing the pattern.

如果指標的型別全都相同,則可以在一個陳述式中初始化多個指標:Multiple pointers can be initialized in one statement if they are all the same type:

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

若要初始化不同類型的指標,只要巢狀 fixed 陳述式即可,如下列範例所示。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.
    }
}

執行陳述式中的程式碼之後,任何固定的變數都會取消固定並受限於記憶體回收。After the code in the statement is executed, any pinned variables are unpinned and subject to garbage collection. 因此,請不要指向 fixed 陳述式之外的變數。Therefore, do not point to those variables outside the fixed statement. fixed 陳述式中所宣告變數的範圍會設為該陳述式,使其更加簡單: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.

fixed 陳述式中初始化的指標是唯讀變數。Pointers initialized in fixed statements are readonly variables. 如果您要修改指標值,則必須宣告第二個指標變數並予以修改。If you want to modify the pointer value, you must declare a second pointer variable, and modify that. fixed 陳述式中宣告的變數無法修改: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.
}

您可以配置堆疊上的記憶體,此處不受記憶體回收限制,因此不需要釘選。You can allocate memory on the stack, where it is not subject to garbage collection and therefore does not need to be pinned. 若要那麼做,請使用 stackalloc 運算子To do that use the stackalloc operator.

C# 語言規格C# language specification

如需詳細資訊,請參閱 C# 語言規格fixed 陳述式一節。For more information, see The fixed statement section of the C# language specification.

另請參閱See also