看引用类型传值和加了ref的引用类型传值的区别
(按值传递和按引用传递的IL区别)
1.这种是一般的没有用ref传值的
public partial class hellowordle : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<prod> stin = new List<prod>();
stin.Add(new prod() { id = "1", name = "111" });
stin.Add(new prod() { id = "2", name = "111" });
stin.Add(new prod() { id = "3", name = "111" });
Myclo(stin);
}
public void Myclo(List<prod> stin)
{
List<prod> stin1 = new List<prod>();
stin1.Add(new prod() { id = "7", name = "111" });
stin1.Add(new prod() { id = "8", name = "111" });
stin = stin.Concat(stin1).ToList();
}
}
public class prod
{
public string id { get; set; }
public string name { get; set; }
}
反编译的代码为:
.method public hidebysig instance void Myclo(class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod> stin) cil managed
{
// 代码大小 98 (0x62)
.maxstack 3
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod> stin1,
[1] class NetNiBiXiuZhiDao.prod '<>g__initLocal3',
[2] class NetNiBiXiuZhiDao.prod '<>g__initLocal4')
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: newobj instance void NetNiBiXiuZhiDao.prod::.ctor()
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldstr "7"
IL_0014: callvirt instance void NetNiBiXiuZhiDao.prod::set_id(string)
IL_0019: nop
IL_001a: ldloc.1
IL_001b: ldstr "111"
IL_0020: callvirt instance void NetNiBiXiuZhiDao.prod::set_name(string)
IL_0025: nop
IL_0026: ldloc.1
IL_0027: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::Add(!0)
IL_002c: nop
IL_002d: ldloc.0
IL_002e: newobj instance void NetNiBiXiuZhiDao.prod::.ctor()
IL_0033: stloc.2
IL_0034: ldloc.2
IL_0035: ldstr "8"
IL_003a: callvirt instance void NetNiBiXiuZhiDao.prod::set_id(string)
IL_003f: nop
IL_0040: ldloc.2
IL_0041: ldstr "111"
IL_0046: callvirt instance void NetNiBiXiuZhiDao.prod::set_name(string)
IL_004b: nop
IL_004c: ldloc.2
IL_004d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::Add(!0)
IL_0052: nop
IL_0053: ldarg.1
IL_0054: ldloc.0
IL_0055: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Concat<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005a: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005f: starg.s stin
IL_0061: ret
} // end of method hellowordle::Myclo
从代码中我们看以看出
IL_0055: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Concat<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005a: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005f: starg.s stin
在没有用ref传值的时候是执行Concat只是得到了一个新的数组,然后把这个数组通过
(Starg.S) | 将位于计算堆栈顶部的值存储在参数槽中的指定索引处。,注意是存储在了 参数槽中,( Myclo(List<prod> stin)的stin的托管堆里面,传过来的是一个拷贝地址) |
下面是使用了ref的传值:
public partial class hellowordle : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
List<prod> stin = new List<prod>();
stin.Add(new prod() { id = "1", name = "111" });
stin.Add(new prod() { id = "2", name = "111" });
stin.Add(new prod() { id = "3", name = "111" });
Myclo(ref stin);
}
public void Myclo(ref List<prod> stin)
{
List<prod> stin1 = new List<prod>();
stin1.Add(new prod() { id = "7", name = "111" });
stin1.Add(new prod() { id = "8", name = "111" });
stin = stin.Concat(stin1).ToList();
}
}
public class prod
{
public string id { get; set; }
public string name { get; set; }
}
.method public hidebysig instance void Myclo(class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>& stin) cil managed
{
// 代码大小 99 (0x63)
.maxstack 3
.locals init ([0] class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod> stin1,
[1] class NetNiBiXiuZhiDao.prod '<>g__initLocal3',
[2] class NetNiBiXiuZhiDao.prod '<>g__initLocal4')
IL_0000: nop
IL_0001: newobj instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::.ctor()
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: newobj instance void NetNiBiXiuZhiDao.prod::.ctor()
IL_000d: stloc.1
IL_000e: ldloc.1
IL_000f: ldstr "7"
IL_0014: callvirt instance void NetNiBiXiuZhiDao.prod::set_id(string)
IL_0019: nop
IL_001a: ldloc.1
IL_001b: ldstr "111"
IL_0020: callvirt instance void NetNiBiXiuZhiDao.prod::set_name(string)
IL_0025: nop
IL_0026: ldloc.1
IL_0027: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::Add(!0)
IL_002c: nop
IL_002d: ldloc.0
IL_002e: newobj instance void NetNiBiXiuZhiDao.prod::.ctor()
IL_0033: stloc.2
IL_0034: ldloc.2
IL_0035: ldstr "8"
IL_003a: callvirt instance void NetNiBiXiuZhiDao.prod::set_id(string)
IL_003f: nop
IL_0040: ldloc.2
IL_0041: ldstr "111"
IL_0046: callvirt instance void NetNiBiXiuZhiDao.prod::set_name(string)
IL_004b: nop
IL_004c: ldloc.2
IL_004d: callvirt instance void class [mscorlib]System.Collections.Generic.List`1<class NetNiBiXiuZhiDao.prod>::Add(!0)
IL_0052: nop
IL_0053: ldarg.1
IL_0054: ldarg.1
IL_0055: ldind.ref
IL_0056: ldloc.0
IL_0057: call class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0> [System.Core]System.Linq.Enumerable::Concat<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>,
class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_005c: call class [mscorlib]System.Collections.Generic.List`1<!!0> [System.Core]System.Linq.Enumerable::ToList<class NetNiBiXiuZhiDao.prod>(class [mscorlib]System.Collections.Generic.IEnumerable`1<!!0>)
IL_0061: stind.ref
IL_0062: ret
} // end of method hellowordle::Myclo
通过上面的代码我们看以看出:
通过ref传址的时候,在执行Concat之前会先去执行ldind.ref
把ref传入的地址压栈,然后Concat出来的新数组会被放入ref传入地址的托管堆里面
然后通过stind.ref保存ref传入地址对应托管堆位置的值
总结:
也就是说:在使用引用类型传址的时候,如果在另外一个方法里面只是对传入的引用类型进行修改或者增加哪可以不用ref传入的引用类型会跟着变化,但是如果在方法里面要对传入的引用类型赋新的地址,哪一定要用ref,不然的情况下,你在方法里面的操作是无效的
(这也是按值传递和引用传递的一个很大的区别)