您的位置:首页 > 其它

.net知识和学习方法系列(二十二)CLR-方法的参数out,ref

2008-10-15 10:40 405 查看
因为数值类型的分类是值类型和引用类型,所以方法的参数也有这两种类型。

值类型参数:

static void Main()

{

int i=1;

Mehtod(i);

}

static void Method(int s)

{

s=200;

}

如果方法的参数是值类型,调用者Main传递给被调用方法Method的是一个值类型的副本,即i的一个副本,i与方法Method中的s值相同,但一旦调用完毕两都就没有关系了。

引用类型:

static void Main()

{

int[] arri=new int[]{1};

Method(arri);

}

static void Method(int[] arrs)

{

Arrs[0]=200;

}

引用类型作为方法的参数时,调用者传递的是引用(与指针类似),即把arri数组的引用传给Method方法,这里只是把引用传递给方法,而非副本,这点就使在Main中的arri与在Method中的arrs引用的是同一个对象,在两个方法的任何地方使之改变都会影响另一个方法的数据的。

简单的说,值类型参数传递副本,引用类型参数传递引用。

接下来说说ref和out作为参数

先看一下下面的代码,

static void F1(ref int i)

{

i = 100;

}

static void F2(out int i)

{

i = 100;

}

看看这两个方法对应的IL

.method private hidebysig static void F1(int32& i) cil managed

{

// 代码大小 6 (0x6)

.maxstack 8

IL_0000: nop

IL_0001: ldarg.0

IL_0002: ldc.i4.s 100

IL_0004: stind.i4

IL_0005: ret

} // end of method Program::F1

.method private hidebysig static void F2([out] int32& i) cil managed

{

// 代码大小 6 (0x6)

.maxstack 8

IL_0000: nop

IL_0001: ldarg.0

IL_0002: ldc.i4.s 100

IL_0004: stind.i4

IL_0005: ret

} // end of method Program::F2

我们通过生成的中间语言看到,这两个方法只有一个差别就是在F2的参数中多了一个[out],方法体中是全部一样的。其实对于CLR来说,这两个关键字是没有区别的,都是能以引用类型的方式来操作参数。

为什么在C#中要区分out和ref呢?主要是因为out是输入参数,只希望它从方法内得到值返回,而ref即要把参数带到方法,也可以带出参数,就是说这只是C#编辑器的愿望,所以在C#中是区别的,但在CLR在运得exe的元数据是不区另的(因为托管理程序是两次编译)。

下面通过另一个方法看看ref和out

static void F1(ref int i)

{

i = 100;

}

static void F1(int i)

{

i = 100;

}

上面的代码放在一个类中是能通过编译的,因为构成了重载

我们看以看一下普通方法的IL

.method private hidebysig static void F1(int32 i) cil managed

{

// 代码大小 6 (0x6)

.maxstack 8

IL_0000: nop

IL_0001: ldc.i4.s 100

IL_0003: starg.s i

IL_0005: ret

} // end of method Program::F1

最明显的差别是参数普通方法是int32 i,而加ref,out的是int32& i,参数的不同使重载成为可以。但ref和out,如果参数类型个数相同的话刚形不成重载,因为它们是相同的,不充许出现相同方法(方法的签名)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: