在后面的例子里,我们得不到3是因为x和y都指向堆里的同一个对象。
{
MyInt x;
x.MyValue = 3;
MyInt y;
y = x;
y.MyValue = 4;
return x.MyValue;
}

希望本文能帮助您更好的理解值类型和引用类型基本的区别,以及指针是什么,什么时候会用到指针。在后面的系列中,我们进一步的阐述内存管理,特别的会多聊聊方法参数的问题。
在Part 1但中,我们简单介绍了堆栈的功能以及值类型、引用类型在堆栈中的存储位置的问题,也简单介绍了指针是虾米。让我们沿着革命的步伐继续前进!
Parameters, the Big Picture.
我们的代码执行的时候,底层到底有哪些内幕交易在发生呢?当我们调用一个方法时:
栈顶分配控件用来存储执行我们的method所包含的信息,这部分空间叫做栈框(stackframe,详情见地板附录)。这里头有一个指针,指向调用地址。通常这是一个GOTO指令,这样线程执行完毕我们的方法后就知道应该回到哪儿去继续执行下一个栈里头的东东。(其实就是把stack frame删掉)
方法的参数被完全复制。这部分我们会做详细解释。
控制权被交给JIT编译好的方法指令集,开始真正的执行代码。实际上,在调用栈中还有另外一个方法,存在于栈框里。(见附录)
代码又来了:
{
int result;
result = pValue + 5;
return result;
}
这时我们的栈看起来这酱紫滴:

就像前面说过的那样,参数如果是值类型,内容会被完整的复制过来。如果是引用类型,被复制的则只是指向堆里头实例的一个指针。
Passing Value Types.
首先,当我们传递一个值类型的时候,栈顶分配相应大小的空间,并且把值完整复制过去。例如:
{
public void Go()
{
int x = 5;
AddFive(x);
Console.WriteLine(x.ToString());
}
public int AddFive(int pValue)
{
pValue += 5;
return pValue;
}
}
当方法被执行时,会给x分配空间,并且值5被赋值到分配好的空间里。

接下来,AddFive被压栈,同时其参数也会压栈(分配空间),然后参数的值会从x,一个字节一个字节的复制过来。

当AddFive结束执行,线程转回到Go方法中。因为AddFive已经没有利用价值了,因此它的参数pValue也跟着没用了,“删之”。
