这只是一个理论问题,但我无法得到一个好的答案:
如果我通过ref
传递参数,则传递对象本身而不是副本。
这让我感到困惑:据我所知,每个方法都有自己的堆栈帧 - 内存,它们不能离开。那么这是否意味着ref-Object被打包在堆上并且有一个对这个参数的引用,或者该方法是否进入调用方法的堆栈并在那里工作?
如果我的问题令人困惑,我很抱歉,我基本上想知道如何保存参考类型以及它有什么影响。
伊迪丝: 我想我没有说清楚。我理解价值和拒绝类型的概念。为了方便起见,我尝试用值类型来解释它,比方说Int:
过程1通过传递Int ByVal来调用Prodecure 2。这个int在Prodecure 2的堆栈上有自己的内存,这意味着,在P2中改变这个值不会改变P1中的值,因为这两个值在每个堆栈中保存一次。
现在与byref相同:Prodecure 2不会保存Int的副本,但可以直接访问此值。 (在我的Oppinion中)有两种可能性来完成这项工作:
这是否更清楚我的意思?
答案 0 :(得分:8)
传递的参数是某个对象的地址。该引用将与该方法的所有其他参数一起传递给堆栈。
在调用方法之前,实际对象本身就存在于它所居住的任何地方。那可能在堆栈中,它可能在堆中,没关系。通过引用传递对象的行为不会导致它在内存中移动,例如从堆栈移动到堆,或者从堆移动到堆栈。
答案 1 :(得分:1)
虽然Servy已经正确地回答了这个问题,但是对于将参数传递给ref
和通过值传递对象的引用之间的区别,似乎存在很多混乱。出于这个原因,我认为值得提供一个简短的说明。
假设以下简单类:
class Player
{
public Player(int health)
{
Health = health;
}
public int Health { get; set; }
}
我们现在可以测试更新对象的属性以及更改引用本身:
static void Main(string[] args)
{
Player player = new Player(100);
Console.WriteLine(player.Health);
ChangeHealth(player);
Console.WriteLine(player.Health);
ChangeHealthByRef(ref player);
Console.WriteLine(player.Health);
ChangePlayer(player);
Console.WriteLine(player.Health);
ChangePlayerByRef(ref player);
Console.WriteLine(player.Health);
}
static void ChangeHealth(Player player)
{
player.Health = 80;
}
static void ChangeHealthByRef(ref Player player)
{
player.Health = 60;
}
static void ChangePlayer(Player player)
{
player = new Player(40);
}
static void ChangePlayerByRef(ref Player player)
{
player = new Player(20);
}
输出:
100
80
60
60
20
ChangeHealth
成功修改了Health
对象的player
属性。
ChangeHealthByRef
也成功修改了Health
对象的player
属性。因此,尽管player
使用了引用的副本,但在两次调用中,您都可以看到ChangeHealth
引用的对象可以被修改。
现在,这是我认为人们感到困惑的部分:
ChangePlayer
创建一个新的Player
对象,用于修改中传递的引用的副本。这意味着更改不会反映在调用代码中(即Health
仍然= 60)。
ChangePlayerByRef
也会创建一个新的Player
对象,但这一次,直接修改引用,这意味着 的更改会在调用代码中反映出来(即Health
= 20)。
答案 2 :(得分:1)