使用[In,Out]和将参数从C#传递给C ++时只使用ref有什么区别吗?
我发现了几个不同的SO帖子,以及来自MSDN的一些内容接近我的问题,但并没有完全回答它。我的猜测是我可以安全地使用ref,就像我使用[In,Out]一样,并且marshaller不会采取任何不同的行动。我担心的是它会采取不同的行为,并且C ++对我传递的C#结构感到满意。我已经在代码库中看到了这两件事,我在......工作。
以下是我发现并一直在阅读的帖子:
Are P/Invoke [In, Out] attributes optional for marshaling arrays? 让我觉得我应该使用[In,Out]。
这三个帖子让我觉得我应该使用[In,Out],但我可以使用ref代替它,它将具有相同的机器代码。这让我觉得我错了 - 因此问这里。
答案 0 :(得分:21)
ref
或out
的使用不是任意的。如果本机代码需要传递引用(指针),那么如果参数类型是值类型,则必须使用这些关键字。这样抖动就知道要生成一个指向该值的指针。如果参数类型是引用类型(类),那么必须省略它们,对象已经成为引擎盖下的指针。
然后需要[In]和[Out]属性来解决指针的歧义,它们不指定数据流。 [in]总是由pinvoke marshaller暗示,因此不必明确说明。但是,如果您希望在代码中看到本机代码对结构或类成员所做的任何更改,那么必须使用[Out]。 pinvoke marshaller避免自动复制以避免费用。
然后进一步的怪癖是[Out]通常不是必需的。当值为 blittable 时发生,这是一个昂贵的单词,表示托管值或对象布局与本机布局相同。然后,pinvoke marshaller可以获取快捷方式,固定对象并将指针传递给托管对象存储。由于本机代码直接修改托管对象,因此您将不可避免地看到更改。
你一般都非常想要追求的东西,它是非常有效的。通过给出[StructLayout(LayoutKind.Sequential)]属性的类型,它可以帮助CLR用来重新排列字段以获得最小对象的优化。并且只使用简单值类型或固定大小缓冲区的字段,尽管您通常不会选择这些字段。切勿使用 bool ,而是使用字节。除了不能正常工作或使用调试器和比较指针值之外,没有简单的方法可以找出类型是否是blittable。
只需明确并在需要时始终使用[Out]。如果事实证明没有必要,它不会花费任何成本。它是自我记录的。如果本机代码的体系结构发生变化,你会感觉它仍然有用。