【问题标题】:Difference between ref and out parameters in .NET [duplicate].NET 中 ref 和 out 参数之间的区别 [重复]
【发布时间】:2010-09-13 05:01:41
【问题描述】:

.NET 中的refout 参数有什么区别?在哪些情况下,一种可能比另一种更有用?一个可以使用而另一个不能使用的代码 sn-p 是什么?

【问题讨论】:

  • 在我看来,这不是上述问题的重复,因为 1. 它在问题 2 之前。此问题中有与“重复”无关的细节。

标签: c# .net


【解决方案1】:

它们几乎相同 - 唯一的区别是您作为 out 参数传递的变量不需要初始化,但作为 ref 参数传递它必须设置为某个值。

int x;
Foo(out x); // OK

int y;
Foo(ref y); // Error: y should be initialized before calling the method

Ref 参数用于可能被修改的数据,out 参数用于作为函数附加输出的数据(例如int.TryParse),这些数据已经在使用返回值。

【讨论】:

  • 另外,在被调用者执行的过程中,out参数必须在返回给调用者之前设置,这与ref相反,ref必须由调用者在调用被调用者之前设置。
  • @Mike 你的更正是错误的。这是正确的“并且使用 out 参数的方法必须将其设置为某个值。”接收out 参数的方法必须对其进行初始化。接收ref 参数的方法可以对其进行任何操作。它肯定可以忽略它。我正在回滚它。
  • 当然,主要区别在于 ref 是 in 和 out,而 out 只能用于返回数据。考虑 void works(ref int z) { Debug.WriteLine(z); } and void notWorks(out int z) { Debug.WriteLine(z);还是我错过了一些技巧来在初始化之前获取输出参数的值?我注意到调试器可以做到这一点。
  • 所以对于必须在输入的过程中设置的参数,应该使用 ref。否则,用完。
  • 从好的方面来说, ref 可以在函数调用期间保存一个额外的 Struct 副本。不利的一面是,一个 Class 可能会被初始化为 null,因此您仍然必须提防这种情况。
【解决方案2】:

Why does C# have both 'ref' and 'out'?

带有out参数的方法的调用者在调用之前不需要分配给作为out参数传递的变量;但是,被调用者需要在返回之前分配给 out 参数。

相比之下,ref 参数被认为是由调用者最初分配的。因此,被调用者不需要在使用前分配给 ref 参数。 Ref 参数传入和传出方法。

所以,out 表示输出,而ref 表示输入和输出。

这些与 COM 接口的[out][in,out] 参数密切对应,out 参数的优点是调用者不需要传递预分配的对象,以防被调用的方法不需要它- 这既避免了分配成本,也避免了可能与封送处理相关的任何成本(更可能与 COM 相关,但在 .NET 中并不少见)。

【讨论】:

  • “相比之下,ref 参数被认为是由被调用者最初分配的”,当然你的意思是“调用者”。我试图编辑您的答案,但它不会让我保存这么小的更改。
  • 该链接对差异有非常清楚的解释,比这里的大多数答案都要好。谢谢!
【解决方案3】:

refout 都允许被调用的方法修改参数。它们之间的区别在于您拨打电话之前会发生什么。

  • ref 表示参数进入函数之前有一个值。被调用的函数可以随时读取和/或更改值。 参数进去,然后出来

  • out表示参数在进入函数之前没有正式的值。被调用的函数必须对其进行初始化。 参数只出去

这是我最喜欢的看待它的方式:ref 是通过引用传递变量。 out 是为函数声明一个次要的返回值。就像你可以这样写:

// This is not C#
public (bool, string) GetWebThing(string name, ref Buffer paramBuffer);

// This is C#
public bool GetWebThing(string name, ref Buffer paramBuffer, out string actualUrl);

以下是每个备选方案的效果的更详细列表:

调用方法前:

ref:调用者必须先设置参数的值,然后再将其传递给被调用的方法。

out:调用者方法不需要在调用方法之前设置参数的值。很可能,你不应该。事实上,任何当前值都会被丢弃。

通话中:

ref:被调用的方法可以随时读取参数。

out:被调用的方法必须在读取参数之前对其进行初始化。

远程调用:

ref:当前值被编组到远程调用。额外的性能成本。

out:没有任何东西传递给远程调用。更快。

从技术上讲,您可以使用 always ref 代替 out,但 out 可以让您更准确地了解参数的含义,有时效率会更高。

【讨论】:

【解决方案4】:

OUT 示例:变量在进入方法后获取值初始化。稍后将相同的值返回给 main 方法。

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            // u can try giving int i=100 but is useless as that value is not passed into
            // the method. Only variable goes into the method and gets changed its
            // value and comes out. 
            int i; 

            a.abc(out i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(out int i)
        {

            i = 10;

        }

    }
}

输出:

10

================================================

Ref 的示例:变量应该在进入方法之前被初始化。稍后相同的值或修改后的值将返回给 main 方法。

namespace outreftry
{
    class outref
    {
        static void Main(string[] args)
        {
            yyy a = new yyy(); ;

            int i = 0;

            a.abc(ref i);

            System.Console.WriteLine(i);
        }
    }
    class yyy
    {

        public void abc(ref int i)
        {
            System.Console.WriteLine(i);
            i = 10;

        }

    }
}

输出:

    0
    10

==================================

希望现在清楚。

【讨论】:

    【解决方案5】:
    • ref 变量需要在传入之前进行初始化。
    • 需要在函数实现中设置out 变量
    • out 参数可以认为是附加的返回变量(不是输入)
    • ref 参数可以被认为是输入和输出变量。

    【讨论】:

      【解决方案6】:

      Ref 和 Out 参数:

      outref 参数用于返回同一个变量中的值,作为方法的参数传递。当您的方法需要返回多个值时,这两个参数非常有用。

      你必须给calee方法体中的out参数赋值,否则方法不会被编译。


      Ref Parameter : 它必须在传递给方法之前进行初始化。 方法参数上的ref 关键字导致方法引用作为同一方法的输入参数传递的同一变量。如果您对变量进行任何更改,它们将反映在变量中。

      int sampleData = 0; 
      sampleMethod(ref sampleData);
      

      参考参数的例子

      public static void Main() 
      { 
       int i = 3; // Variable need to be initialized 
       sampleMethod(ref i );  
      }
      
      public static void sampleMethod(ref int sampleData) 
      { 
       sampleData++; 
      } 
      

      Out 参数: 在传递给 Method 之前不必初始化。 out 参数可用于返回作为方法参数传递的同一变量中的值。对参数所做的任何更改都会反映在变量中。

       int sampleData; 
       sampleMethod(out sampleData);
      

      Ex of Out 参数

      public static void Main() 
      { 
       int i, j; // Variable need not be initialized 
       sampleMethod(out i, out j); 
      } 
      public static int sampleMethod(out int sampleData1, out int sampleData2) 
      { 
       sampleData1 = 10; 
       sampleData2 = 20; 
       return 0; 
      } 
      

      【讨论】:

        【解决方案7】:

        输出:

        在 C# 中,一个方法只能返回一个值。如果要返回多个值,可以使用 out 关键字。 out 修饰符作为返回引用返回。最简单的答案是关键字“out”用于从方法中获取值。

        • 您不需要在调用函数中初始化值。
        • 必须在被调用函数中赋值,否则编译器会报错。

        参考:

        在 C# 中,当您将 int、float、double 等值类型作为参数传递给方法参数时,它是按值传递的。因此,如果修改参数值,不会影响方法调用中的参数。但是如果你用“ref”关键字标记参数,它会反映在实际变量中。

        • 您需要在调用函数之前初始化变量。
        • 在方法中为 ref 参数分配任何值不是强制性的。如果不改变值,有什么必要将其标记为“ref”?

        【讨论】:

          【解决方案8】:

          函数中不需要设置ref参数,而out参数必须在退出函数之前绑定一个值。作为 out 传递的变量也可以在没有初始化的情况下传递给函数。

          【讨论】:

            【解决方案9】:

            out指定参数为输出参数,即在方法明确设置之前没有值。

            ref 指定该值是具有值的引用,并且您可以在方法内更改其值。

            【讨论】:

              【解决方案10】:

              out参数由调用的方法初始化,ref参数在调用方法之前初始化。因此,out 参数用于当您只需要获取次要返回值时,ref 参数用于获取值并且可能返回对该值的更改(次要返回到主返回值)。

              【讨论】:

                【解决方案11】:

                ref 关键字用于通过引用传递值。 (这并不排除传递的值是值类型或引用类型)。用 out 关键字指定的输出参数用于从方法返回值。

                代码中的一个关键区别是您必须在方法中设置输出参数的值。这不是 ref 参数的情况。

                更多详情请看http://www.blackwasp.co.uk/CSharpMethodParameters.aspx

                【讨论】:

                  【解决方案12】:

                  out 参数是添加了特殊Out() 属性的ref 参数。如果 C# 方法的参数被声明为out,编译器将要求在读取参数和方法返回之前写入参数。如果 C# 调用其参数包含Out() 属性的方法,编译器将为了决定是否报告“未定义变量”错误,假装该变量是在调用该方法之前立即写入的。请注意,由于其他 .net 语言没有将相同的含义附加到 Out() 属性,因此使用 out 参数调用例程可能会使相关变量不受影响。如果一个变量在被明确分配之前被用作out 参数,C# 编译器将生成代码以确保它在使用之前的某个时间点被清除,但如果这样的变量离开并重新进入范围,则不保证会再次被清除。

                  【讨论】:

                    【解决方案13】:

                    ref 可能会因 null 而窒息,因为它可能希望修改现有对象。 out 期望 null,因为它返回一个新对象。

                    【讨论】:

                    • Foo(ref null) 不会编译,但是 string bar = null; Foo(参考栏);很好。
                    • 空常量阻塞?作为 James Curran,您不能在 ref 参数中传递常量。
                    • 我的意思不是空常量:我指的是具有空值的变量。
                    【解决方案14】:

                    out 和 ref 完全相同,只是 out 变量在发送到深渊之前不必初始化。我没那么聪明,我从 MSDN 库中抄来的 :)。

                    然而,为了更明确地说明它们的使用,修饰符的含义是,如果您在代码中更改该变量的引用,out 和 ref 将导致您的调用变量也更改引用。在下面的代码中,一旦从对 doStuff 的调用返回,ceo 变量将是对 newGuy 的引用。如果不是用于 ref(或 out),则不会更改引用。

                    private void newEmployee()
                    {
                        Person ceo = Person.FindCEO();
                        doStuff(ref ceo);
                    }
                    
                    private void doStuff(ref Person employee)
                    {
                        Person newGuy = new Person();
                        employee = newGuy;
                    }
                    

                    【讨论】:

                      【解决方案15】:

                      这个The out and ref Paramerter in C#有一些很好的例子。

                      概述的基本区别是out参数在传入时不需要初始化,而ref参数则需要。

                      【讨论】:

                        【解决方案16】:

                        它们有细微的不同。

                        out 参数在传递给方法之前不需要由被调用者初始化。因此,任何带有out 参数的方法

                        • 在赋值之前无法读取参数
                        • 返回前必须为其赋值

                        这用于需要覆盖其参数而不考虑其先前值的方法。


                        ref 参数在传递给方法之前必须由被调用者初始化。因此,任何带有ref 参数的方法

                        • 可以在分配之前检查值
                        • 可以返回原始值,不受影响

                        这用于必须(例如)检查其值并对其进行验证或规范化的方法。

                        【讨论】:

                          【解决方案17】:

                          out 在 C#7 中获得了更简洁的新语法 https://docs.microsoft.com/en-us/dotnet/articles/csharp/whats-new/csharp-7#more-expression-bodied-members 更令人兴奋的是 C#7 元组增强功能,它是比使用 ref 和 out 恕我直言更优雅的选择。

                          【讨论】:

                            猜你喜欢
                            • 1970-01-01
                            • 1970-01-01
                            • 2011-12-05
                            • 2011-03-11
                            • 2012-09-24
                            • 1970-01-01
                            • 2018-12-29
                            相关资源
                            最近更新 更多