通常我们向方法中传递的是值,方法获得的是这些值的一个拷贝,然后使用这些拷贝,当方法运行完毕后,这些拷贝将被丢弃,而原来的值不会受到影响。 这种情况是通常的,当然还有另外一种情况,我们向方法传递参数的形式,引用(ref)和输出(out)。
有时,我们需要改变原来变量中的值,这是我们可以向方法传递变量引用,而不是变量的值,引用是一个变量,他可以访问原来变量的值,修改引用将修改原来变量的值。变量的值存储在内存中,可以创建一个引用,他指向变量在内存中的位置,当引用被修改时,修改的是内存中的值,因此变量的值可以被修改,当我们调用一个含有引用参数的方法时,方法中的参数将指向被传递给方法的相应变量,因此,我们会明白为什么当修改参数变量的修改也将导致原来变量的值被修改。
ref
using System; using System.Collections.Generic; using System.Linq; namespace ConsoleAppTest { class Program { static void Main(string[] args) { Gump gump = new Gump(); List<int> list = new List<int>(); double a = 3; gump.AddInt(1,ref list); gump.AddInt(2, ref list); gump.AddInt(3, ref list); Console.WriteLine($"a={a}"); Console.WriteLine(string.Join(",", list.Select(x => x.ToString()))); Console.ReadLine(); } } class Gump { public double Square(ref double x) { x = x * x; return x; } public void AddInt(int i, ref List<int> list) { list.Add(i); } } }
out
using System; using System.Collections.Generic; using System.Linq; namespace ConsoleAppTest { class Program { static void Main(string[] args) { Gump doit = new Gump(); double x1 = 10; double cubed1 = 0; double squared1 = 0; double half1 = 0; doit.math_routines(x1, out half1, out squared1, out cubed1); Console.WriteLine("Before method->x1={0}", x1); Console.WriteLine("Before method->half1={0}", half1); Console.WriteLine("Before method->squared1={0}", squared1); Console.WriteLine("Before method->cubed1={0}", cubed1); doit.math_routines(x1, out half1, out squared1, out cubed1); Console.WriteLine("After method->x1={0}", x1); Console.WriteLine("After method->half1={0}", half1); Console.WriteLine("After method->squared1={0}", squared1); Console.WriteLine("After method->cubed1={0}", cubed1); Console.ReadLine(); } } class Gump { public void math_routines(double x, out double half, out double squared, out double cubed) //可以是:public void math_rotines(//ref double x,out double half,out double squared,out double cubed) //但是,不可以这样:public void math_routines(out double x,out double half,out double squared,out double cubed) //对本例子来说,因为输出的值要靠X赋值,所以X不能再为输出值 { half = x / 2; squared = x * x; cubed = x * x * x; } public void AddInt(int i, out List<int> list1, out List<int> list2) { //引用类型 out 要先实例化 list1 = new List<int>(); list2 = new List<int>(); if (i % 2 == 1) { list1.Add(1); } } } }
通过制定返回类型,可以从方法返回一个值,有时候,需要返回多个值,虽然我们可以使用ref来完成,但是C#专门提供了一个属性类型,关键字为out,介绍完后,我们将说明ref和out的区别。
我们发现,ref和out似乎可以实现相同的功能,因为都可以改变传递到方法中的变量的值,但是二者本质的区别就是,ref是传入值,out是传出值,在含有out关键之的方法中,变量 必须有方法参数中不含out(可以是ref)的变量赋值或者由全局(即方法可以使用的该方法外部变量)变量赋值,out的宗旨是保证每一个传出变量都必须被赋值
在传入变量的时候,out关键字的变量可以不被初始化,但是没有out 关键字的值要被赋值。而ref参数在传递给方法是,就已经被赋值了,所以ref侧重修改,out侧重输出。