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 语句将为托管变量设置一个指针,并在该语句的执行过程中“单边锁定”该变量。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. GetPinnableReference 必须向非托管类型返回 ref 变量。The GetPinnableReference must return a ref variable to an unmanaged type. 请参阅有关指针类型的主题以了解详细信息。See the topic on pointer types for more information. .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