方向特性
每个方法参数都可以与 InAttribute 特性和/或 OutAttribute 特性的设置关联。 可以在设计时应用方向特性以修改托管和非托管内存之间的运行时封送处理。
InAttribute 和 OutAttribute 位于 System.Runtime.InteropServices 命名空间中,且等效于接口定义语言 (IDL) 接口特性 [in]、[out]、[in/out] 和 [out, retval]。
备注
托管方法签名的返回值始终映射到类型库中的 [out, retval]。没有可以应用的等效方向特性。
方向特性是可选的。 可以在希望改变封送拆收器的默认行为时将它们应用于方法参数。 如果忽略来自方法参数的方向特性,则封送拆收器将根据参数的类型(值或引用)及其修饰符(如果有的话)确定方向流。
某些语言提供使您能够修改方法参数的方向流的关键字。 下表列出了 Visual Basic 2005 和 C# 所提供的与方向有关的关键字并显示等效的 IDL 接口特性。
Visual Basic 2005 |
C# |
IDL 特性 |
---|---|---|
ByVal |
无等效项。 |
[in] |
ByRef |
ref |
[in/out] |
无等效项。 |
out |
[out] |
ByRef、ref 和 out 参数修饰符导致方法参数通过引用而不是通过值进行封送。 通过值传递的方法参数被作为堆栈上的值封送到非托管代码;通过引用传递的参数被作为堆栈上的指针封送。 下面的插图显示具有参数修饰符的值类型和引用类型的默认封送处理行为。
将方法参数封送到非托管代码的默认封送处理
默认情况下,通过值传递的引用类型(类、数组、字符串和接口)出于性能原因而作为 In 参数封送。 只有将 InAttribute 和 OutAttribute(或仅将 OutAttribute)应用于方法参数才能看见对这些类型所做的更改。 StringBuilder 类(它是本规则的一个例外)作为 In/Out 参数进行封送处理。
Interop 封送拆收器保证下列与方向特性有关的行为:
Interop 封送拆收器从不生成对从非托管代码传递的 In 参数的写操作。 因此,非托管代码可以安全地传递指向只读页的指针,或传递指向被同时访问的数据的指针。
当复制的对象包含已分配的对象(如 BSTR)时,封送拆收器总是执行 In/Out 设置所要求的正确的分配和销毁顺序。
在代码中准确地应用方向特性十分重要。 在托管代码中将 InAttribute 和 OutAttribute 正确地应用于参数将确保类型库导出程序 (Tlbexp.exe) 使用这些位来设置相应类型库中的 In/Out 位;这对于可以锁定的引用类型(如某些数组和类)尤为重要。