.NET中ref和out参数的区别

412

在.NET中,refout参数有什么区别?它们各自更加适用的场景是什么?能否提供一个使用其中一种参数而另一种无法使用的代码片段?


在我看来,这不是所提到的问题的重复,因为1.它先于那个问题2.这个问题中有一些与“重复”无关的细节。 - Dov Miller
17个回答

510

它们基本上是一样的 - 唯一的区别是,你作为 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),这些数据已经使用返回值进行了某些操作。


102
此外,在调用方返回之前,必须在被调用方执行期间设置输出参数,这与 ref 相反,后者必须在调用被调用方之前由调用方设置。 - Jesse C. Slicer
3
@Mike你的更正是错误的。 "使用out参数的方法必须将其设置为某些内容" 才是正确的。接收out参数的方法必须初始化它。接收ref参数的方法可以随意使用它。它可以忽略它。我正在回滚它。 - xanatos
2
当然,主要的区别在于 ref 是输入输出参数,而 out 只能用于返回数据。考虑以下两个函数:void works(ref int z) { Debug.WriteLine(z); } 和 void notWorks(out int z) { Debug.WriteLine(z); } 我是否错过了一些技巧,可以在初始化 out 参数之前获取其值?我注意到调试器可以做到这一点。 - user159335
因此,对于必须在传入参数时设置为某个值的参数,应使用 ref。否则,请使用 out。 - FistOfFury
1
好处是,ref 可以在函数调用期间避免额外复制结构体。坏处是,类可以初始化为 null,因此仍然必须防范这种情况。 - Michael Brown
显示剩余2条评论

134

为什么C#中有'ref'和'out'两种参数?

一个使用'out'参数的方法的调用者在调用前不需要为传递的变量赋值; 但是,被调用的方法必须在返回前将'out'参数赋值。

相反,'ref'参数被认为是由调用者初始化的。因此,在使用之前,被调用方不需要为'ref'参数赋值。'ref'参数同时被传入和传出方法。

因此,'out'表示输出,而'ref'则表示输入和输出。

这与COM接口的'[out]'和'[in,out]'参数密切对应。使用'out'参数的优点在于,调用者在不需要被调用方法使用预分配对象的情况下不需要传递一个 - 这避免了分配的成本以及可能与封送相关的任何成本(在COM中更常见,但在.NET中也很常见)。


3
相比之下,引用参数被认为是由调用方最初分配的,你肯定是指“调用者”。我试图编辑您的答案,但无法保存这样微小的更改。 - fpsColton
这个链接对于这个区别有非常清晰的解释,比大多数答案都要好。谢谢! - Hannish

85

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:没有东西传递到远程调用。更快。

技术上讲,你可以始终使用ref来代替out,但out允许你对参数的含义更加精确,并且有时它可以更加高效。


1
作为C# 7的一部分,之前被称为“这不是C#” 的代码行现在实际上已经是C#了。请参考https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#tuples。 - TJ Rockefeller

19

OUT示例:变量在进入方法后获得初始化值。稍后,相同的值将返回到主方法。

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

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

示例参考:在进入方法之前应该初始化变量。稍后,相同的值或修改后的值将返回到主方法。

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;

        }

    }
}

Output:

    0
    10
希望现在清楚了。

10
  • 在传递之前需要初始化ref变量。
  • out变量需要在函数实现中进行设置。
  • out参数可以被看作是额外的返回变量(而不是输入)。
  • ref参数可以被看作是既有输入又有输出的变量。

9

Ref和Out参数:

outref参数用于将返回值保存在与传递给方法的变量相同的变量中。当方法需要返回多个值时,这两个参数非常有用。

必须在调用方法体中为out参数分配值,否则该方法将无法编译。


Ref Parameter : It has to be initialized before passing to the Method. The ref keyword on a method parameter causes a method to refer to the same variable that was passed as an input parameter for the same method. If you do any changes to the variable, they will be reflected in the variable.

int sampleData = 0; 
sampleMethod(ref sampleData);
< p > Ref参数示例

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

public static void sampleMethod(ref int sampleData) 
{ 
 sampleData++; 
} 

Out Parameter : It is not necessary to be initialized before passing to Method. The out parameter can be used to return the values in the same variable passed as a parameter of the method. Any changes made to the parameter will be reflected in the variable.

 int sampleData; 
 sampleMethod(out sampleData);

输出参数示例

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

out:

C#中的方法只能返回一个值。如果您想要返回多个值,可以使用out关键字。out修饰符返回的是引用传递。简单地说,“out”关键字用于从方法获取值。

  • 您不需要在调用函数中初始化该值。
  • 必须在被调用的函数中分配该值,否则编译器将报告错误。

ref:

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

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

4

out表示该参数是输出参数,即在方法显式设置之前没有值。

ref指定该值是一个具有值的引用,在方法内部可以更改其值。


4

Ref参数在函数中不是必须设置的,而out参数必须绑定一个值后才能退出函数。作为out传递的变量也可以在未初始化的情况下传递到函数中。


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

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