默认情况下,CLR假定所有方法参数都是传值的。
对于引用类型,对一个对象的引用(指向对象的一个指针)会传给方法,但是这个引用本身是以传值的方式传给方法的。方法能修改对象,调用者能看到这些修改。
对于值类型,传给方法的是实例的一个副本。方法获得的是一个值类型实例副本,所以调用者中的实例不受影响。
代码如下:
namespace refDemo2 { class Program { static void Main(string[] args) { int i = 5; AddI(i); Console.WriteLine(i);//显示"5",i的值并没有改变 Console.ReadKey(); } private static void AddI(int v)//v获得的是i的一个副本,调用者中的实例不受影响 { v+= 10; } } }
一,为值类型使用ref和out
namespace refDemo2 { class Program { static void Main(string[] args) { int i = 5; AddI(ref i); Console.WriteLine(i);//显示"15",i的值被改变了 Console.ReadKey(); } private static void AddI(ref int v)//v获得的是一个指向实例对象(值5)的指针 { v+= 10; } } }
二,为引用类型使用ref和out
namespace refDemo3 { class Program { static void Main(string[] args) { string s1 = "Tmac"; string s2 = "Mcgrady"; Swap(s1,s2);//没有使用ref Console.WriteLine(s1);//显示"Tmac" Console.WriteLine(s2);//显示"Mcgrady",为什么值没有交换呢??? } private static void Swap(string a, string b)//a和b获取的是一个分别指向对象s1和s2的指针 { string t = b; b = a; a = t; } } }
容易困惑的地方:s1,s2是引用类型,传给方法Swap的肯定也是指向实例的一个指针,那理论上来讲调用了Swap方法之后s1和s2的值要交换呀,可是实际结果并不如我们所愿,这是为什么呢?
答:就如文章一开头讲的,默认情况下,CLR假定所有方法参数都是传值的,虽然s1和s2是引用类型,调用方法时传递的也是指向实例的指针,但是,指针本身还是以传值方式传给方法的。所以调用者中实例的值并没有得到改变。
要达到我们想要的效果,所以还是必须得使用ref,代码如下:
namespace refDemo3 { class Program { static void Main(string[] args) { string s1 = "Tmac"; string s2 = "Mcgrady"; Swap(ref s1,ref s2); Console.WriteLine(s1);//显示"Mcgrady" Console.WriteLine(s2);//显示"Tmac" } private static void Swap(ref string a,ref string b)//a和b获取的是一个分别指向对象s1和s2的指针 { string t = b; b = a; a = t; } } }
总结:1,从IL和CLR的角度看,ref和out是一样的,它们都会生成相同的IL代码,都导致传递指向实例的一个指针。
2,ref一般用在方法内部对外部的值进行改变的时候。而out一般用在方法有多个返回值的时候。