我想模仿以下方法:
ref class Something{
void foo(array<double>^% data)
{
data = gcnew array<double>(10);
}
};
这样,调用者的数组被修改/创建。然而,有一些限制因素:
是否可以使用非托管指针,IntPtr或更隐蔽的方式来实现?
答案 0 :(得分:2)
没有。如果foo的实际参数是对象的句柄,则无法更改调用堆栈的引用。
您需要使用跟踪引用才能影响传递给方法的句柄。
编辑以回应AZ的评论:
这不起作用的原因是,当你有效地传递一个Object句柄时,除了对象在内存中的位置外,你只传递它。从本质上讲,这基本上只是一个保存内存位置的整数。
在方法中指定新对象时,您将覆盖该位置(放置一个新整数)。这不会改变调用者的原始句柄,因为它只是一个副本。这是传递参数的常规方法。
通过使用跟踪引用,您将传递对内存中位置的引用。这有点像在C或C ++中传递指针。当您这样做时,您可以更改引用指向的位置(它的值)而不更改引用本身 - 仅更改它引用的内容。
答案 1 :(得分:1)
- foo不能使用ref / out /%或任何其他参数。
- foo的实际参数必须是Object ^。
醇>
调用者可以分配数组并将其传入,并且您可以修改数组中的元素 - 但这只是将数组转换为Object并再次返回。
如果要更改实际数组 - 例如将其分配给不同长度的新数组,而不使用ref
(C ++ / CLI中为%
)或out
({{ 1}}在C ++ / CLI中,你不能这样做。
原因如下:
.NET虚拟机通过将内容推送到堆栈来工作。将参数传递给函数的方式在幕后工作如下:
如果调用者在调用函数之前没有在栈上放置有效数据,它就会崩溃。如果调用者以错误的顺序放入数据 - 它会崩溃。如果堆栈中任何东西都很有趣 - 它会崩溃。
此外,方法无法修改堆栈中已有的内容。 (如果他们这样做了,他们会破坏堆栈 - 崩溃),他们只能在堆栈上下推出新东西。
这意味着两件事:
为了调用该函数,您必须将对数组的引用放入堆栈中。因此调用者必须自己分配数组,或传递空引用。
您无法更改对数组的引用,因此该函数无法提供新数组。由于数组本身不可调整大小,这意味着您无法添加新元素(但您可以更改现有元素)
免责声明:Eric lippert可能会来解释为什么我刚写的所有内容都是错误的,但就我所知和研究而言,这就是它的工作原理