值类型和引用类型问题
嗨,我正在尝试做两个对象的简单交换。我的代码是
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
内部的First
和Second
对象的引用,但参数本身对于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; }