【问题标题】:The <Out()> Attribute. What useful purpose does is serve?<Out()> 属性。有什么用处?
【发布时间】:2011-01-24 11:29:26
【问题描述】:

System.Runtime.InteropServices 下存在&lt;Out()&gt; 属性。 但它是为了什么?如果您可以使用以下示例作为您的答案的基础,我会很高兴。

 Shared Sub Add(ByVal x As Integer, ByVal y As Integer, <Out()> ByRef Result As Integer)
  Result = x + y
 End Sub

【问题讨论】:

    标签: .net vb.net attributes output-parameter


    【解决方案1】:

    该属性的目的是双重的:

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

    如果您要从 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 使用的方法调用上指定,则在调用该方法时不会对现有参数值进行编组,但是当方法调用时返回它的值被提升回你的调用代码中。

    请注意,此优化取决于编组例程是否使用,这些是实现细节。该属性只是告诉例程它可以使用哪些参数来执行此操作,而不是始终遵循的指令。

    【讨论】:

      【解决方案2】:

      这意味着参数被 C# 视为“输出”参数,一方面。在这种情况下,C# 编译器会假定:

      • 通过引用传递的变量的任何现有值都无关紧要,因此明确的赋值无关紧要
      • 变量在方法返回时被分配一个适当的值,除非有异常 - 所以它肯定是在语句末尾分配的。

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

      【讨论】:

      • 只有在编译相关代码时,这对 C# 来说不重要吗?调用站点上的“ref”和“out”不是相同的吗? - 没关系:)
      • 实际上,这意味着如果在调用相关例程之前没有写入变量,编译器将静默插入代码来初始化保存变量的存储位置,而不是抱怨它(无法保证此类代码将放置在何处;也无法保证离开并重新进入范围的变量在不重新初始化的情况下不会继续使用相同的存储位置)。编译器不能真正假设变量是被写入的,因为它不能确定被调用的例程实际上是在写入它。
      • @supercat:这取决于我们考虑的程度。 “检查您的源代码是否有效”级别确实假定变量已写入。 “发射 IL”级别不会 - 尽管针对不同平台的不同实现可能能够。
      【解决方案3】:

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

      【讨论】:

        【解决方案4】:

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

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

        如果您使用 COM oder p-invoke,它可能会对编组产生影响。

        【讨论】:

          【解决方案5】:

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

          在某些情况下[OutAttribute] 将被忽略。例如,[OutAttribute]int 没有任何意义,因此 CLR 会简单地忽略 [OutAttribute][OutAttribute] 字符串也是如此,因为字符串是不可变的。

          因此,对于您的示例,此属性没有意义。有关此属性和相关&lt;In()&gt; 属性的更多信息,您可以找到here

          【讨论】:

            猜你喜欢
            • 2011-02-22
            • 1970-01-01
            • 1970-01-01
            • 2010-11-12
            • 2013-08-08
            • 2014-09-12
            • 1970-01-01
            • 2012-10-19
            • 1970-01-01
            相关资源
            最近更新 更多