向 Windows 运行时组件传递数组
在 Windows 运行时中,参数用于输入或输出,但从不同时用于输入和输出。 这意味着,传递给方法的数组内容以及数组本身用于输入或输出。 如果数组的内容用于输入,则方法会从数组中读取,但不向其中写入内容。 如果数组的内容用于输出,则方法会向数组中写入内容,但不从其中读取内容。 这会给数组参数带来问题,因为 .NET framework 中的数组是引用类型,并且即使数组引用通过值(Visual Basic 中的 ByVal)传递,数组的内容也是可变的。 Windows 运行时元数据导出工具 (Winmdexp.exe) 要求通过将 ReadOnlyArrayAttribute 特性或 WriteOnlyArrayAttribute 特性应用于参数来指定数组的用途(如果未在上下文中明确指定)。 可按下述方式确定数组用途:
对于返回值或 out 参数(在 Visual Basic 中具有 OutAttribute 特性的 ByRef 参数),数组始终仅用于输出。 不要应用 ReadOnlyArrayAttribute 特性。 输出参数中允许 WriteOnlyArrayAttribute 特性,但它是冗余的。
警告
Visual Basic 编译器不强制“仅输出”规则。不应从输出参数中读取;它可能包含 Nothing。始终分配新数组。
不允许使用具有 ref 修饰符(在 Visual Basic 中为 ByRef)的参数。 Winmdexp.exe(Windows 运行时元数据导出工具)生成错误。
对于通过值传递的参数,必须通过应用 ReadOnlyArrayAttribute 特性或 WriteOnlyArrayAttribute 特性指定数组内容用于输入还是输出。 同时指定两个特性是错误的。
如果方法必须接受用于输入的数组,请修改数组内容并将该数组返回给调用方,将只读参数用于输入,将只写参数(或返回值)用于输出。 以下代码演示用于实现此模式的一种方法:
public int[] ChangeArray([ReadOnlyArray()] int[] input)
{
int[] output = input.Clone();
// Manipulate the copy.
// ...
return output;
}
Public Function ChangeArray(<ReadOnlyArray> input() As Integer) As Integer()
Dim output() As Integer = input.Clone()
' Manipulate the copy.
' ...
Return output
End Function
建议你立即创建输入数组的副本并操作该副本。 这有助于确保无论 .NET framework 代码是否调用你的组件,该方法的行为都相同。
使用托管和非托管代码中的组件
根据调用方是用本机代码还是托管代码编写的,具有 ReadOnlyArrayAttribute 特性或 WriteOnlyArrayAttribute 特性的参数会有不同的行为。 如果调用方是本机代码(JavaScript 或 Visual C++ 组件扩展),则按如下方式处理数组内容:
ReadOnlyArrayAttribute:在调用跨越应用程序二进制接口 (ABI) 边界时复制数组。 必要时会转换元素。 因此,该方法对仅输入数组所做的任何意外更改对调用方而言均不可见。
WriteOnlyArrayAttribute:所调用的方法不能针对原始数组的内容做任何假设。 例如,该方法接收的数组可能无法初始化或可能包含默认值。 该方法应设置数组中所有元素的值。
如果调用方是托管代码,则原始数组可供调用的方法使用,正如它在 .NET Framework 中的任何方法调用中一样。 NET Framework 代码中的数组内容是可变的,因此该方法对数组进行的任何更改对调用方而言都是可见的。 记住这一点非常重要,因为它会影响为 Windows 运行时组件编写的单元测试。 如果用托管代码编写测试,则数组内容在测试期间将显示为可变。