关键字 `in, out, ref` 与属性 `[In], [Out], [In, Out]`

lan*_*ngs 7 c# marshalling

我知道第一组关键字in, out, ref可以在所有 C# 函数中使用,第二组属性[In], [Out], [In, Out]用于 marshaller。

我不确定它们在本机代码的函数声明中使用时是否表示相同的意思。例如,以下两个声明是否等效?

[DllImport("xxx.dll")]
void FillArray1(ref int[] arr, in int length);

[DllImport("xxx.dll")]
void FillArray2([In, Out] int[] arr, [In] int length);
Run Code Online (Sandbox Code Playgroud)

是否存在两个集合不等价的情况?

Gyö*_*zeg 5

它们并不等同。

对于 ,ref int[] arr默认[In, Out]属性会自动应用,但它仍然与[In, Out] int[] arr.

ref int[] arr是双重间接寻址(通过引用传递的引用类型)。如果本机端定义如下所示,请使用此选项:int32_t** arr。这不仅允许替换元素,还允许替换整个数组实例。

另一方面,[In, Out] int[] arr是按值传递的简单引用。如果本机端也使用单间接,则使用此选项,例如。int32_t* arr。通常在 C# 中,如果按值传递数组(这是引用类型),则被调用的方法可以替换元素,这将从调用方反映出来。然而,P/Invoke 封送处理的工作方式有点不同

In默认情况下,出于性能原因,按值传递的引用类型(类、数组、字符串和接口)将被封送为参数。InAttribute除非您将and OutAttribute(或仅OutAttribute)应用于方法参数,否则您不会看到这些类型的更改。

因此,无论指定属性如何,本机端都会获得正确的指针Out[Out]封送拆收器需要在此处进行指定,这样它就不会忽略到托管内存的回拷会话。

类似地,将传递对整数的引用,并且与仅按值传递参数的in int length不同。[In] int length可以[In]省略,因为这是这种情况下的默认封送行为。