<Out()>属性。它有什么有用的作用?

9
System.Runtime.InteropServices 下存在 <Out()> 属性。但是它有什么作用呢?如果您能以以下示例为基础回答,我会很高兴的。
 Shared Sub Add(ByVal x As Integer, ByVal y As Integer, <Out()> ByRef Result As Integer)
  Result = x + y
 End Sub
5个回答

8

该属性有两个目的:

  • 调用站点处理,是否强制变量初始化
  • 编组

如果您从C#或类似语言具有类似语义的语言调用该方法,则编译器将知道此类参数不需要初始值。

换句话说,您可以这样做:

int a;
CallSomeMethodWithOutParameter(out a);

编译器知道在调用之前无需确保a已经有值。

另一方面,如果没有该属性,以下内容将需要在C#中再次执行:

int a = 0;                               // <-- notice initialization here
CallSomeMethodWithOutParameter(ref a);   // <-- and ref here

另一个目的是为了方法调用,这些调用将被编组到不同的调用上下文中,例如通过P / Invoke,到不同的应用程序域或到Web服务,以通知编组例程在方法返回时参数将包含一个值,但在调用它时没有必要传递任何值到该方法中。
当需要打包参数和返回值并将其传输到实际调用的远程位置时,这可能会产生差异。
换句话说,如果您在通过P / Invoke使用的方法调用中指定不对现有参数值进行编组,则在调用方法时不会进行编组,但在方法返回后,其值将返回到您的调用代码中。
请注意,这种优化取决于编组例程是否使用这些实现细节。 属性只告诉例程可以使用哪些参数,而不是一定会遵循的指令。

3
这意味着参数被C#视为 "out" 参数。在这种情况下,C#编译器会假定:
  • 通过引用传递的变量的任何现有值都是无关紧要的,因此确定赋值并不重要
  • 除非出现异常,否则该变量将在方法返回时被分配一个适当的值 - 因此它在语句结束时是明确分配的。

当然,其他语言可能会以不同的方式使用 [Out] 属性,但这种解释是最自然的。基本上,它表示参数几乎就像是一个额外的返回值。(当然,有很多差异,程度不同,但这是 out 参数的一般感觉。)


算了,这个问题只有在编译相关代码时才会影响C#,"ref"和"out"在调用时不是完全相同的吗? - Lasse V. Karlsen
实际上,这意味着如果在调用相关例程之前可能没有写入变量,则编译器将默默地插入代码以初始化保存变量的存储位置,而不是抱怨它(关于放置此类代码的位置没有任何保证;也没有保证离开并重新进入范围的变量不会继续使用相同的存储位置而不重新初始化)。编译器无法真正假定变量已被写入,因为它无法确定所调用的例程实际上是否写入了它。 - supercat
@supercat:这取决于我们考虑事情的层次。在“检查源代码是否有效”的层面上,确实假定了变量已经被编写。而在“发出IL”级别上则不是这样 - 尽管针对不同平台的不同实现可能能够做到。 - Jon Skeet

2

在ComVisible类型中使用它,表示生成的COM类型库应该使用[out]属性装饰参数。


0

我不知道VB,但假设它相当于C#的out关键字:

outref的行为类似,但是不需要调用者初始化传递给out参数的变量,因为函数不会读取它。

如果使用COM或p-invoke,则可能会影响封送处理。


0

在应用于方法参数和返回值时,这些属性控制了编组方向,因此被称为方向属性。 [OutAttribute] 告诉 CLR 在返回时从被调用方到调用方进行编组。调用方和被调用方都可以是非托管或托管代码。例如,在 P/Invoke 调用中,托管代码调用非托管代码。但是,在反向 P/Invoke 中,非托管代码可以通过函数指针调用托管代码。

有些情况下,[OutAttribute] 将被忽略。例如,[OutAttribute]int 没有任何意义,因此 CLR 简单地忽略了 [OutAttribute]。对于不可变的字符串,[OutAttribute] 同样适用。

因此,对于您的示例,此属性没有意义。关于此属性和相关的 <In()> 属性,您可以在 这里 找到更多信息。


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