fixed ステートメント (C# リファレンス)fixed Statement (C# Reference)

fixed ステートメントは、移動可能な変数がガベージ コレクターにより再配置されることを防ぎます。The fixed statement prevents the garbage collector from relocating a movable variable. fixed ステートメントは、unsafe コンテキストでのみ許可されます。The fixed statement is only permitted in an unsafe context. fixed キーワードは、固定サイズ バッファーの作成にも使うことができます。You can also use the fixed keyword to create fixed size buffers.

fixed ステートメントは、マネージド変数へのポインターを設定し、ステートメントの実行中にその変数を "固定" します。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 ステートメントでマネージド変数へのポインターを割り当てることだけができます。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 ステートメントは、配列、文字列、固定サイズ バッファー、アンマネージド型変数以外の型でも動作します。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. GetPinnableReferenceref 変数をアンマネージド型にして返す必要があります。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.

複数のポインターは、すべて同じ型の場合、1 つのステートメントで初期化できます。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. ポインター値を変更するには、2 つ目のポインター変数を宣言し、それを変更する必要があります。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