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

7
我知道第一组关键字in,out,ref可以在所有C#函数中使用,而第二组属性[In],[Out],[In,Out]则是为了马克罗。但是,我不确定当它们用于本机代码的函数声明时是否具有相同的含义。例如,下面两个声明是否等效?
[DllImport("xxx.dll")]
void FillArray1(ref int[] arr, in int length);

[DllImport("xxx.dll")]
void FillArray2([In, Out] int[] arr, [In] int length);

这两个集合有没有可能不等同?

我不确定 InOut 属性的作用是什么,但是关键字 inout 在编译时会被检查(用于只读/只写访问),并且参数是按引用传递而不是按值传递。通常可以通过反射在运行时查询属性。 - Zereges
1个回答

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 marshaling的工作方式有些differently:

默认情况下,按值传递的引用类型(类、数组、字符串和接口)出于性能原因将作为 In 参数进行编组。除非您将 InAttributeOutAttribute(或只使用 OutAttribute)应用于方法参数,否则您不会看到这些类型的更改。
因此,无论是否指定 Out 属性,本机端都会获得正确的指针。在这里指定 [Out] 是为了使编组器不会省略回复到托管内存的传输会话。
同样地,in int length 将传递一个整数的引用,并且与 [In] int length 不同,后者仅通过值传递参数。可以省略 [In],因为这是在此情况下的默认编组行为。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接