值类型和引用类型问题

嗨,我正在尝试做两个对象的简单交换。我的代码是

void Main() { object First = 5; object Second = 10; Swap(First, Second); //If I display results it displays as //Value of First as 5 and Second as 10 } private static void Swap(object First, object Second) { object temp = First; First = Second; Second = temp; } 

由于对象是引用类型,因此应将其引用传递给方法,并且应该交换。 为什么不发生?

这里有各种不同的东西:

  • 对象在堆中存活。 暂时忘掉它们吧
  • 对象引用是存储在First和第二个中的内容
  • 你在Main有两个变量
  • Swap有两个参数

现在; 重要的是“引用类型/引用”和“通过引用传递”之间的区别。 它们完全不相关

在线:

 Swap(First, Second); 

您将两个变量传递给Swap 。 在这种情况下, First / Second对盒装对象引用

下一个;

 private static void Swap(object First, object Second) { object temp = First; First = Second; Second = temp; } 

在这里,您交换两个本地参数的值,但这些参数完全独立于其他任何参数。 如果我们希望调用者看到的更改(即重新分配),我们需要通过引用传递:

 private static void Swap(ref object First, ref object Second) { object temp = First; First = Second; Second = temp; } 

现在, First的值不再是对盒装对象的引用; 它是对盒装对象的引用的引用 。 在来电者,我们使用:

 Swap(ref First,ref Second); 

这意味着传递变量First的引用 ,而不是传递变量First的值

请注意,我说你可以忘记有一个物体的事实? 如果我们使用以上所有内容完全相同:

 int x = 1, y = 2; Swap(ref x, ref y); void Swap(ref int a, ref int b) { var tmp = a; a = b; b = tmp; } 

唯一的区别是x是1等,而ref x是对变量x的引用。 在通过引用传递时,引用类型与值类型完全无关; 唯一重要的是要理解你默认传递变量的值,其中变量的1 (等),或“对象的引用”。 无论哪种方式,逻辑都是一样的。

以这种方式看待它。

让我们将交换方法中的参数重命名为“x”和“y”,因为它们与本地人相同只是令人困惑。

你有一个苹果和一个橘子。 两个对象。

你有两张纸说“APPLE”和“ORANGE”。 这些是对象的引用。

你有两个盒子,一个标记为First,另一个标记为Second。

你把“APPLE”放在第一位,把“ORANGE”放在第二位。

现在你再获得两个标有x和y的方框。

你制作APPLE的复印件并把它放在x中。 你制作一个ORANGE的复印件,并把它放在y。

现在你交换x和y的内容。 APPLE和ORANGE仍然是引用,但您没有更改First和Second的内容。 你改变了x和y的内容。

现在假设您将“ref”添加到参数x和y的声明中。 现在这意味着:

你有两个盒子,一个标记为First,另一个标记为Second。

你把“APPLE”放在第一位,把“ORANGE”放在第二位。

您将新标签添加到第一个框; 它现在也可以被称为x。 第二个也可以称为y。

你交换了x和y的内容。 由于它们只是第一个和第二个的别名,因此交换第一个和第二个的内容。

合理?

Swap方法中的参数指向的对象是对Main内部的FirstSecond对象的引用,但参数本身对于Swap方法是本地的。

所以如果你在Swap里面写过First = 1; Second = 2 First = 1; Second = 2 ;你会看到Main里面对象的变化。 但是,您只需更改Swap 指向的参数(通过将它们分配给另一个对象),并且根本不更改对象。 如果您尝试在Swap方法中将对象设置为null ,情况也是如此。

您没有将它作为引用传递,您需要明确声明您正在传递引用:

  Swap(ref First,ref Second); private static void Swap(ref object First,ref object Second) 

您是按值传递对象的引用(传递值是C#中的默认值)。

相反,您需要通过引用将对象传递给函数(使用ref关键字)。

 private static void Swap(ref object first, ref object second) { object temp = first; first = second; second = temp; } void Main() { object first = 5; object second = 10; Swap(ref first, ref second); } 

当然,如果您使用的是C#2.0或更高版本,那么最好定义一个可以接受任何类型参数的函数的generics版本,而不是object类型。 例如:

 private static void Swap(ref T first, ref T second) { T temp; temp = first; first = second; second = temp; } 

然后你也可以用适当的类型int声明变量。

不是通过值传递对象的引用,而是需要通过引用传递它们。 换句话说,您需要传递对该对象的引用的引用

这是使用ref关键字实现的。

例如

 private static void Swap(ref object First, ref object Second) { object temp = First; First = Second; Second = temp; } 

你需要通过引用传递。

这里有一些关于pass-by-refence,pass-by-value的额外信息: http : //www.yoda.arachsys.com/csharp/parameters.html ,试试这个:

 void Main() { object First = 5; object Second = 10; Swap(ref First, ref Second); //If I display results it displays as //Value of First as 5 and Second as 10 } private static void Swap(ref object First, ref object Second) { object temp = First; First = Second; Second = temp; }