我正在创建一个函数,我需要传递一个对象,以便它可以被函数修改。有什么区别:

public void myFunction(ref MyClass someClass)

and

public void myFunction(out MyClass someClass)

我应该用哪个,为什么?


当前回答

裁判上场又出局。

您应该优先使用out,只要它能满足您的需求。

其他回答

裁判上场又出局。

您应该优先使用out,只要它能满足您的需求。

简洁的回答。

ref和out关键字都用于引用传递。 关键字为ref的变量必须有一个值或必须引用一个对象 或者在它传递之前为null。 与ref不同,关键字为out的变量必须有一个值或必须 在对象传递后引用对象或null以及不需要 在传递之前有一个值或引用一个对象。

ref和out就像c++中传递引用和传递指针一样。

对于ref,参数必须声明并初始化。

对于out,实参必须声明,但可以初始化,也可以不初始化

        double nbr = 6; // if not initialized we get error
        double dd = doit.square(ref nbr);

        double Half_nbr ; // fine as passed by out, but inside the calling  method you initialize it
        doit.math_routines(nbr, out Half_nbr);

为了说明这些优秀的解释,我开发了以下控制台应用程序:

using System;
using System.Collections.Generic;

namespace CSharpDemos
{
  class Program
  {
    static void Main(string[] args)
    {
      List<string> StringList = new List<string> { "Hello" };
      List<string> StringListRef = new List<string> { "Hallo" };

      AppendWorld(StringList);
      Console.WriteLine(StringList[0] + StringList[1]);

      HalloWelt(ref StringListRef);
      Console.WriteLine(StringListRef[0] + StringListRef[1]);

      CiaoMondo(out List<string> StringListOut);
      Console.WriteLine(StringListOut[0] + StringListOut[1]);
    }

    static void AppendWorld(List<string> LiStri)
    {
      LiStri.Add(" World!");
      LiStri = new List<string> { "¡Hola", " Mundo!" };
      Console.WriteLine(LiStri[0] + LiStri[1]);
    }

    static void HalloWelt(ref List<string> LiStriRef)
     { LiStriRef = new List<string> { LiStriRef[0], " Welt!" }; }

    static void CiaoMondo(out List<string> LiStriOut)
     { LiStriOut = new List<string> { "Ciao", " Mondo!" }; }
   }
}
/*Output:
¡Hola Mundo!
Hello World!
Hallo Welt!
Ciao Mondo!
*/

AppendWorld: A copy of StringList named LiStri is passed. At the start of the method, this copy references the original list and therefore can be used to modify this list. Later LiStri references another List<string> object inside the method which doesn't affect the original list. HalloWelt: LiStriRef is an alias of the already initialized ListStringRef. The passed List<string> object is used to initialize a new one, therefore ref was necessary. CiaoMondo: LiStriOut is an alias of ListStringOut and must be initialized.

因此,如果一个方法只是修改了被传递的变量引用的对象,编译器不会让你使用out,你也不应该使用ref,因为它不仅会让编译器困惑,而且会让代码的读者困惑。如果该方法将使传递的参数引用另一个对象,则对于已经初始化的对象使用ref,对于必须为传递的参数初始化新对象的方法使用out。除此之外,ref和out的行为是一样的。

Ref告诉编译器对象在进入函数之前已经初始化,而out告诉编译器对象将在函数内部初始化。

所以当ref是双向的,out是唯一的。