他们的局限性更大。你可以在指针上说 ++,但不能在ref
or out
.
EDIT注释中有些混乱,所以要绝对清楚:这里的重点是与指针的功能进行比较。您无法执行与以下操作相同的操作ptr++
on a ref
/out
,即使其寻址内存中的相邻位置。确实(但与此无关)您可以执行相当于(*ptr)++
,但这将是将其与values,而不是指针。
可以肯定的是,它们在内部只是指针,因为堆栈不会移动,并且 C# 是经过精心组织的,因此ref
and out
始终引用堆栈的活动区域。
EDIT再次绝对清楚(如果从下面的示例中还不清楚的话),这里的重点不是ref
/out
can only指向堆栈。就是那个when它指向堆栈,语言规则保证它不会成为悬空指针。这种保证是必要的(并且在这里相关/有趣),因为堆栈只是根据方法调用退出丢弃信息,而没有检查以确保任何引用者仍然存在。
反之当ref
/out
引用 GC 堆中的对象,这些对象能够根据需要保持活动状态也就不足为奇了:GC 堆的设计正是为了将对象保留其引用者所需的任何时间长度,并提供固定(请参阅下面的示例)以支持不能通过 GC 压缩移动对象的情况。
如果您曾经在不安全的代码中使用过互操作,您会发现ref
与指针密切相关。例如,如果 COM 接口声明如下:
HRESULT Write(BYTE *pBuffer, UINT size);
互操作程序集会将其变成这样:
void Write(ref byte pBuffer, uint size);
你可以这样做来调用它(我相信 COM 互操作的东西负责固定数组):
byte[] b = new byte[1000];
obj.Write(ref b[0], b.Length);
换句话说,ref
到第一个字节可以让您访问所有内容;它显然是指向第一个字节的指针。