fixed 语句(C# 参考)
fixed
语句可防止垃圾回收器重新定位可移动的变量。 fixed
语句仅允许存在于不安全的上下文中。 还可以使用 fixed
关键字创建固定大小的缓冲区。
fixed
语句将为托管变量设置一个指针,并在该语句的执行过程中“单边锁定”该变量。 仅可在 fixed
上下文中使用指向可移动托管变量的指针。 如果没有 fixed
上下文,垃圾回收可能会不可预测地重定位变量。 C# 编译器只允许将指针分配给 fixed
语句中的托管变量。
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
语句可在数组、字符串、固定大小缓冲区或非托管变量以外的其他类型上执行。 实施名为 GetPinnableReference
的方法的任何类型都可以被固定。 GetPinnableReference
必须返回非托管类型 的 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 语句部分。