C# 什么时候有必要/合适使用InAttribute和OutAttribute进行COM互操作
我正在尝试整理我们分散在各个项目中的COM互操作定义,并将它们收集到一个已知的好位置,整个开发团队都可以从中受益。这项工作的一部分涉及清理多年来积累的定义 其中一些是从其他源代码中借用的,一些是从pinvoke.net中逐字复制的,还有一些看起来是直接从SDK头中翻译出来的。我注意到的一件事是,关于何时使用各种编组属性没有一致性(即使在pinvoke.net示例中,这也是非常成功的)。问题的一部分是,我认为这里的任何人(包括我自己)都不完全理解何时需要或不需要各种属性,或者它们实际做什么。到目前为止,要把这些翻译正确似乎是猜测和随机变化的结合,直到COMExceptions停止发生,但我更希望翻译是正确的,因为有人真的看了它们并宣称它们是正确的 所以,我从C# 什么时候有必要/合适使用InAttribute和OutAttribute进行COM互操作,c#,com-interop,C#,Com Interop,我正在尝试整理我们分散在各个项目中的COM互操作定义,并将它们收集到一个已知的好位置,整个开发团队都可以从中受益。这项工作的一部分涉及清理多年来积累的定义 其中一些是从其他源代码中借用的,一些是从pinvoke.net中逐字复制的,还有一些看起来是直接从SDK头中翻译出来的。我注意到的一件事是,关于何时使用各种编组属性没有一致性(即使在pinvoke.net示例中,这也是非常成功的)。问题的一部分是,我认为这里的任何人(包括我自己)都不完全理解何时需要或不需要各种属性,或者它们实际做什么。到目前
[In]
和[Out]
开始。我知道这两个属性在概念上的作用:它们通知封送员数据必须流向哪个方向。例如,我假设封送处理程序不会费心将[In]
数据复制回调用者,或者知道[Out]
数据可能需要在被调用者端释放,等等。我不知道的是:
[In]
是错误的,但是标记输入参数[In,Out]
实际上会破坏任何东西吗HRESULT Foo(
[in] ULONG a,
[out] ULONG * b
[in, out] ULONG * c);
我可能会将其翻译为以下任何一种:
void Foo(
uint cb,
out uint b,
ref uint c);
void Foo(
uint cb,
[Out] out uint b,
[In, Out] ref uint c);
void Foo(
[In] uint cb,
[Out] out uint b,
[In, Out] ref uint c);
这三者在功能上有什么不同吗?除了技术正确性之外,是否有任何一个被认为比其他属性“更好”呢?不,严格来说,没有必要在您自己的代码中应用这些属性中的任何一个。它们都是可选的,并根据参数的类型自动应用于代码 本质上,它们具有以下C#关键字等价物:
- 默认情况下,您将获得
[In]
关键字可以获取ref
[In,Out]
关键字可以获取out
[out]
[In]
属性标记声明的参数ref
,以抑制封送处理的“out”部分
也就是说,我发现自己在使用它们,因为它们是一种非常简单的代码自记录方法。我喜欢自记录的想法!只需补充一点:Bool和string使用MarshalAs更为相关,请检查这些……是的,我对MarshalAs属性更为熟悉,尽管其中有一些细节我还不清楚(主要是数组)。我开始很简单:)啊,这实际上解释了我在pinvoke.net上看到的很多东西!例如,如果一个方法采用refid参数,则通常为“ref Guid”。但是如果该参数在IDL中被指定为[in],我可以将其指定为“[in]ref-Guid-refid”,并且它不会费事将Guid结构封送给我,因为我不需要它,对吗?@Michael:是的,没错。您将无法看到对结构所做的任何修改,但如果您不需要这些修改,那么将其标记为
[In]ref
就可以了。这就是说,这绝对是一个微观优化,可能不值得为它的正确性付出太多努力。如果我理解正确,ref
和out
关键字也增加了间接性。例如,如果您有一个类X
,那么在托管代码中说f(out X)
就像在非托管代码中说f(**X)
。因此,如果非托管签名是f(*x)
,其中x被修改,则必须使用[Out]
属性(或使x成为结构)。资料来源:这里要小心,你在比较苹果和桔子。IDL文件中的[in]和[out]属性仅由midl.exe在生成代理/存根代码时使用。仅当需要在单元或进程之间封送COM调用时才使用。.NET[In]和[Out]属性仅由pinvoke marshaller使用。它运行在一个完全不同的运行时环境中,始终处于进程中,不考虑单元。他们的意图当然是一样的,优化通话。是的,我(想我)理解这一部分。出于我的目的,在将IDL转换为C#时,我只使用IDL属性作为方法“应该”如何运行的提示。注意,IDL中的[out]属性意味着接口编写器希望该参数从调用方返回,并在其中存储一个值,因此我需要确保C#代码以相同的方式运行。我的不足之处在于理解.NET封送处理程序的默认行为,以及何时我需要告诉它该做什么,而不是何时它自己做正确的事情。它们在IDL中是必要的,因为使用指针时完全不清楚数据流的方向。使用ref和out关键字在C#中不是问题。99%的好例子只是省略了C#中的属性。如果您实际使用C#替换COM代码,则为100%。