在C#中使用pinvoke时,和ref之间有什么区别?

使用[In,Out]和将参数从C#传递给C ++时只使用ref有什么区别吗?

我发现了几个不同的SOpost,以及来自MSDN的一些东西也接近我的问题,但并没有完全回答它。 我的猜测是我可以安全地使用ref,就像我使用[In,Out]一样,并且marshaller将不会采取任何不同的行为。 我担心的是它会采取不同的行为,并且C ++对我传递的C#结构不满意。 我已经在我正在使用的代码库中看到了两件事情……

以下是我发现并一直在阅读的post:

P / Invoke [In,Out]属性是否可选用于编组数组? 让我觉得我应该使用[In,Out]。

  • MSDN:InAttribute
  • MSDN:OutAttribute
  • MSDN:定向属性

这三个post让我觉得我应该使用[In,Out],但我可以使用ref代替它,它将具有相同的机器代码。 这让我觉得我错了 – 所以问这里。

refout的使用不是任意的。 如果本机代码需要传递引用(指针),那么如果参数类型是值类型,则必须使用这些关键字。 这样抖动就知道要生成一个指向该值的指针。 如果参数类型是引用类型(类),则必须省略它们,对象已经是引擎盖下的指针。

然后需要[In]和[Out]属性来解决指针的歧义,它们不指定数据流。 [in]始终由pinvoke marshaller暗示,因此不必明确说明。 但是,如果您希望在代码中看到本机代码对结构或类成员所做的任何更改,则必须使用[Out]。 pinvoke marshaller避免自动复制以避免费用。

那么进一步的怪癖是[Out]通常不是必需的。 当值为blittable时发生,这是一个昂贵的单词,表示托管值或对象布局与本机布局相同。 然后,pinvoke marshaller可以获取快捷方式,固定对象并将指针传递给托管对象存储。 由于本机代码直接修改托管对象,因此您将不可避免地看到更改。

你一般都非常想要追求的东西,它是非常有效的。 您可以通过给出[StructLayout(LayoutKind.Sequential)]属性类型来帮助它抑制CLR用于重新排列字段以获取最小对象的优化。 并且只使用简单值类型或固定大小缓冲区的字段,尽管您通常不会有这种选择。 永远不要使用bool ,而是使用byte 。 除了不能正常工作或使用调试器和比较指针值之外,没有简单的方法可以确定类型是否是blittable。

只需要明确,并在需要时始终使用[Out]。 如果事实certificate没有必要,它不会花费任何成本。 它是自我记录的。 如果本机代码的体系结构发生变化,那么它仍然会感觉很好。