Welcome

首页 / 软件开发 / .NET编程技术 / 解析.net中ref和out的实质

解析.net中ref和out的实质2011-03-31 csdn博客 傅晗可能是.net中的value type和reference type的关系遇到给函数传递参数的情况时, 在我们的脑海里就会浮现按值和按引用传递的概念。如果看见下面这个函数(代码1)我 们就会条件反射似的说要给参数加上ref才能使函数内部修改参数的值。

//代码1

void Change(int a, int b)
{
int tmp = a;
a = b;
b = tmp
}

ok,那继续看下面这个代码

//代码2

void Change2(object o)
{
o = new object();
}

static void Main()
{
object obj = null;
Change2(obj);
Console.WriteLine(obj ?? "null");
}

null? object不是引用类型吗,为什么在函数内对引用类型赋值却没有改变参数的值 呢?因为答案只有一个:“所有的参数传递都是按值传递的”。 不要被值类型和引用类 型所迷惑,也不要被ref,out关键字所迷惑。如果你了解c或者c++那么这个问题很好理解 ,所谓ref,out关键字(这两个关键字在IL级别上是相同的,只是在语法上规定ref修饰 的参数必须赋值,out修饰的参数可以不赋值。以此区分out这个语义)对于c来说ref int == int*而ref object == object**,而对于c++来说ref int == int&而ref object == object*&.如果你不懂c和c++也没关系,下面我通过反汇编来说明ref和out的本质 ,有如下测试代码:

//代码3

static void Ref_Out(ref int a, out int b, int c)
{
a = 15;
b = 127;
c = 99;
}
static void Main()
{
int i1 = -1; //ref要有初始值
int i2; //out不需要
Ref_Out(ref i1, out i2, i1);
Console.WriteLine(i1.ToString() + " " + i2.ToString()); //15 127
}

ok让我们运行程序吧,请在上面代码行12出设置断点。程序运行到断点后查看一下当 前寄存器状态

EBP = 0012F480(栈底) ESP = 0012F440(栈顶) EIP = 0103009D

这时候我们单步进入Ref_Out函数并在代码行03出设置断点,这时候的寄存器状态为

EBP = 0012F434 ESP = 0012F3F4 EIP = 010300ab ECX = 0012F444 EDX = 0012F440 ESI = 0012F440 EDI = 0012F444