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

public void myFunction(ref MyClass someClass)

and

public void myFunction(out MyClass someClass)

我应该用哪个,为什么?


当前回答

下面是一个同时使用Ref和out的例子。现在,你们都可以离开裁判了。

在下面提到的例子中,当我注释//myRefObj = new myClass {Name = "ref outside called!! ""}; 行,将得到一个错误说“使用未分配的局部变量'myRefObj'”,但没有这样的错误在out。

在哪里使用Ref:当我们调用带有in形参的过程时,该形参将用于存储该过程的输出。

在哪里使用Out:当我们调用一个没有in形参的过程时,相同的参数将用于返回该过程的值。 还要注意输出

public partial class refAndOutUse : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        myClass myRefObj;
        myRefObj = new myClass { Name = "ref outside called!!  <br/>" };
        myRefFunction(ref myRefObj);
        Response.Write(myRefObj.Name); //ref inside function

        myClass myOutObj;
        myOutFunction(out myOutObj);
        Response.Write(myOutObj.Name); //out inside function
    }

    void myRefFunction(ref myClass refObj)
    {
        refObj.Name = "ref inside function <br/>";
        Response.Write(refObj.Name); //ref inside function
    }
    void myOutFunction(out myClass outObj)
    {
        outObj = new myClass { Name = "out inside function <br/>" }; 
        Response.Write(outObj.Name); //out inside function
    }
}

public class myClass
{
    public string Name { get; set; }
} 

其他回答

: return语句只能用于从函数中返回一个值。但是,使用输出参数,可以从一个函数返回两个值。输出参数类似于引用参数,只是它们将数据传输出方法而不是传输到方法中。

下面的例子说明了这一点:

using System;

namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void getValue(out int x )
      {
         int temp = 5;
         x = temp;
      }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;

         Console.WriteLine("Before method call, value of a : {0}", a);

         /* calling a function to get the value */
         n.getValue(out a);

         Console.WriteLine("After method call, value of a : {0}", a);
         Console.ReadLine();

      }
   }
}

裁判: 引用形参是对变量内存位置的引用。与值参数不同,通过引用传递参数时,不会为这些参数创建新的存储位置。引用参数表示与提供给方法的实际参数相同的内存位置。

在c#中,使用ref关键字声明引用参数。下面的例子说明了这一点:

using System;
namespace CalculatorApplication
{
   class NumberManipulator
   {
      public void swap(ref int x, ref int y)
      {
         int temp;

         temp = x; /* save the value of x */
         x = y;   /* put y into x */
         y = temp; /* put temp into y */
       }

      static void Main(string[] args)
      {
         NumberManipulator n = new NumberManipulator();
         /* local variable definition */
         int a = 100;
         int b = 200;

         Console.WriteLine("Before swap, value of a : {0}", a);
         Console.WriteLine("Before swap, value of b : {0}", b);

         /* calling a function to swap the values */
         n.swap(ref a, ref b);

         Console.WriteLine("After swap, value of a : {0}", a);
         Console.WriteLine("After swap, value of b : {0}", b);

         Console.ReadLine();

      }
   }
}

“贝克”

这是因为第一个将字符串引用更改为指向“Baker”。更改引用是可能的,因为您通过ref关键字传递了它(=>是对字符串引用的引用)。 第二个调用获取字符串引用的副本。

弦一开始看起来很特别。但字符串只是一个引用类,如果你定义

string s = "Able";

那么s是一个包含文本“Able”的字符串类的引用! 对同一个变量via的另一个赋值

s = "Baker";

不改变原来的字符串,但只是创建一个新的实例,让我们指向该实例!

你可以试试下面的小代码示例:

string s = "Able";
string s2 = s;
s = "Baker";
Console.WriteLine(s2);

你想要什么? 您将得到的仍然是“Able”,因为您只是将s中的引用设置为另一个实例,而s2指向原始实例。

编辑: String也是不可变的,这意味着根本没有修改现有字符串实例的方法或属性(你可以尝试在文档中找到一个,但你找不到:-))。所有字符串操作方法都会返回一个新的字符串实例!(这就是为什么你在使用StringBuilder类时经常会得到更好的性能)

 public static void Main(string[] args)
    {
        //int a=10;
        //change(ref a);
        //Console.WriteLine(a);
        // Console.Read();

        int b;
        change2(out b);
        Console.WriteLine(b);
        Console.Read();
    }
    // static void change(ref int a)
    //{
    //    a = 20;
    //}

     static void change2(out int b)
     {
         b = 20;
     }

你可以检查这段代码,它会向你描述它的完全不同 当你使用“ref”时,这意味着你已经初始化了int/string

但 当你使用out的时候 无论你是否初始化int/string,它都适用于这两种情况 但是u必须在函数中初始化int/string

我要试着解释一下:

我想我们理解了值类型是如何工作的,对吧?值类型是(int, long, struct等)。当你将它们发送到一个没有ref命令的函数时,它会复制数据。在函数中对该数据所做的任何操作都只会影响副本,而不会影响原始数据。ref命令发送的是实际数据,任何变化都会影响函数外部的数据。

好了,让人困惑的部分,引用类型:

让我们创建一个引用类型:

List<string> someobject = new List<string>()

当你新建someobject时,会创建两部分:

存储某对象数据的内存块。 指向该块的引用(指针) 的数据。

现在,当你发送someobject到一个没有引用的方法时,它复制的是引用指针,而不是数据。现在你得到了这个:

(outside method) reference1 => someobject
(inside method)  reference2 => someobject

两个引用指向同一个对象。如果你使用reference2修改某个对象的属性,它将影响由reference1指向的相同数据。

 (inside method)  reference2.Add("SomeString");
 (outside method) reference1[0] == "SomeString"   //this is true

如果你清空了reference2或将其指向新的数据,它不会影响reference1和reference1所指向的数据。

(inside method) reference2 = new List<string>();
(outside method) reference1 != null; reference1[0] == "SomeString" //this is true

The references are now pointing like this:
reference2 => new List<string>()
reference1 => someobject

当你将someobject by ref发送给方法时会发生什么? 对某个对象的实际引用被发送给方法。所以你现在只有一个数据引用:

(outside method) reference1 => someobject;
(inside method)  reference1 => someobject;

但这意味着什么呢?它的作用与不通过ref发送someobject完全相同,除了两件主要的事情:

1)当你清空方法内部的引用时,它也会清空方法外部的引用。

 (inside method)  reference1 = null;
 (outside method) reference1 == null;  //true

2)你现在可以将引用指向一个完全不同的数据位置,函数外部的引用现在将指向新的数据位置。

 (inside method)  reference1 = new List<string>();
 (outside method) reference1.Count == 0; //this is true

有两个主要的区别,我想举例说明:

Ref和out通过reference传递,hense;

 class Program
    {
        public static void Main(string[] args)
        {
            var original = new ObjectWithMememberList(3);
            Console.WriteLine(original.MyList.Capacity); // 3
            ChangeList(original.MyList);
            Console.WriteLine(original.MyList.Capacity); // 3
        }

        static void ChangeList(List<int> vr)
        {
            vr = new List<int>(2);
        }
}

but:

 class Program
    {
        public static void Main(string[] args)
        {
            var original = new ObjectWithMememberList(3);
            Console.WriteLine(original.MyList.Capacity); // 3
            ChangeList(ref original.MyList);
            Console.WriteLine(original.MyList.Capacity); // 2
        }

        static void ChangeList(ref List<int> vr)
        {
            vr = new List<int>(2);
        }
}

out也是一样。 2. Ref参数必须是一个可赋值变量。 hense:

ChangeList(ref new List<int>()); // Compile Error [might not be initialized before accessing]

but:

List<int> xs;
ChangeList(out xs); // Compiles