在C#中使用pinvoke时,[In,Out]和ref之间有什么区别

本文关键字:ref 之间 区别 什么 Out pinvoke In | 更新日期: 2023-09-27 18:23:43

在将参数从C#传递到C++时,使用[In,Out]和仅使用ref有区别吗?

我发现了几篇不同的SO帖子,以及MSDN中的一些内容,这些内容与我的问题很接近,但并没有完全回答。我的猜测是,我可以像使用[In,Out]一样安全地使用ref,并且马歇尔不会有任何不同的行为。我担心的是,它的行为会有所不同,C++不会对我的C#结构被传递感到满意。我在我工作的代码库中看到了这两件事…

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

p/Invoke[In,Out]属性对于封送阵列是可选的吗?让我觉得我应该使用[In,Out]。

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

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

在C#中使用pinvoke时,[In,Out]和ref之间有什么区别

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

[In]和[Out]属性是解决指针模糊性所必需的,它们不指定数据流。[In]总是由pinvoke-masseller隐含的,因此不必明确说明。但是,如果希望在代码中看到本机代码对结构或类成员所做的任何更改,则必须使用[Out]。pinvokemarshaller避免了自动回拷贝以避免开销。

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

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

当您希望字段得到更新时,请明确并始终使用[Out]。如果它被证明是不必要的,那么它不需要任何费用。它是自我记录的。如果本机代码的体系结构发生变化,它仍然可以工作,这让您感觉很好。