.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,如果参数类型个数相同的话刚形不成重载,因为它们是相同的,不充许出现相同方法(方法的签名)。
值类型参数:
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,如果参数类型个数相同的话刚形不成重载,因为它们是相同的,不充许出现相同方法(方法的签名)。
相关文章推荐
- .net知识和学习方法系列(二十二)CLR-方法的参数out,ref
- .net知识和学习方法系列(十一)Main方法的参数与返回值
- .net知识和学习方法系列(二十一)CLR-枚举
- .net知识和学习方法系列(十六)CLR-托管理程序和它的运行
- .net知识和学习方法系列(十七)CLR-CLR中的值类型和引用类型
- .net知识和学习方法系列(十)委托异步调用方法b
- .net知识和学习方法系列(四)继承中方法的隐藏和重写
- .net知识和学习方法系列(二十)CLR-委托
- .net知识和学习方法系列(四)继承中方法的隐藏和重写
- .net知识和学习方法系列(二十)CLR-委托
- .net知识和学习方法系列(十六) CLR-托管理程序和它的运行
- .net知识和学习方法系列(十九)CLR-事件
- 读<<CLR via C#>>总结(7) 以传引用的方式向方法传递参数---ref&out
- .net知识和学习方法系列(十八)CLR-构造函数
- .net知识和学习方法系列(十八)CLR-构造函数
- .net知识和学习方法系列(九)委托异步调用方法a
- .net知识和学习方法系列(二十一)CLR-枚举
- .net知识和学习方法系列(十六)CLR-托管理程序和它的运行
- C# 参考之方法参数关键字:params、ref及out
- ref out 方法参数