扫一扫
分享文章到微信
扫一扫
关注官方公众号
至顶头条
当将参数传递给方法时,它们可能通过值传递,也可能通过引用传递。值参数只提取任何变量的值以在方法中使用,因而调用代码中的变量值不受方法中对这些参数所执行的操作的影响。
而引用型参数指向在调用代码中声明的变量,因而在通过引用传递时,方法将修改该变量的内容。
在 Java 和 C# 中,引用对象的方法参数总是通过引用传递,而基本数据类型参数则通过值传递。
在 C# 中,所有参数在默认情况下都是通过值传递的。要通过引用进行传递,我们需要指定关键字 ref 或 out 中的一个。这两个关键字的不同之处在于参数的初始化。ref 参数必须在使用前进行初始化,而 out 参数无需在传递前进行显式初始化,并且任何先前的值都会被忽略。
请注意,当方法将引用类型作为参数使用时,引用本身是通过值传递的。然而,引用仍然指向内存中的同一对象,因此对对象的属性所做的任何改变在方法退出之后将保持不变。但是,因为引用本身是通过值传递的,所以在方法内它应该改为指向一个不同的对象甚至一个新对象,而一旦方法执行完毕,引用就会恢复为指向原来的对象,即使原来的对象是未赋值的也同样如此。
当我们希望调用的方法永久性地改变用作参数的变量的值时,我们可以在参数中指定此关键字。发生传递的不是在调用中使用的变量值,而是对变量本身的引用。然后,方法作用于引用,这样,在方法执行过程中对参数所做的更改就保存到用作方法的参数的原始变量中。
下面的代码用 Add() 方法对此进行了说明,其中,第二个 int 参数是使用 ref 关键字通过引用传递的:
using System; public class RefClass { public static void Main(string[] args) { int total = 20; Console.WriteLine("Original value of 'total': {0}", total); // Call the Add method Add (10, ref total); Console.WriteLine("Value after Add() call: {0}", total); } public static void Add (int i, ref int result) { result += i; } }
这个简单示例的输出结果表明,对 result 参数所做的改变反映在 Add() 调用所用的变量 total 中:
Original value of 'total': 20 Value after Add() call: 30
这是因为 result 参数引用了调用代码中的 total 变量所占用的实际内存位置。请注意,类的属性不是一个变量,并且不能直接用作 ref 类型的参数。
注意,在调用方法时,ref 关键字必须在参数之前,在方法声明中同样如此。
out 关键字的作用与 ref 关键字非常相似,并且对使用 out 关键字声明的参数所做的修改在方法外是可见的。它与 ref 有两点不同:首先,out 参数的任何初始值在方法中都是忽略的;其次,out 参数必须在方法中赋值:
using System; public class OutClass { public static void Main(string[] args) { int total = 20; Console.WriteLine("Original value of 'total': {0}", total); Add (33, 77, out total); Console.WriteLine("Value after Add() call: {0}", total); } public static void Add (int i, int j, out int result) { // The following line would cause a compile error // Console.WriteLine("Initial value inside method: {0}", result); result = i + j; } }
在该示例中,Add() 方法的第三个参数是用 out 关键字声明的,并且对该方法的调用还需要将 out 关键字用于该参数。输出结果为:
Original value of 'total': 20Value after Add() call: 110
因此,总的来说,当您希望方法修改现有的变量时,可以使用 ref 关键字,而使用 out 关键字来返回在该方法中产生的值。当方法为调用代码产生多个结果值时,通常一起使用 out 关键字与该方法的返回值。
通过在声明方法时指定 params 关键字,C# 允许我们发送可变数目的参数。参数列表也可以包含普通参数,但是需要注意,用 params 关键字声明的参数必须放在最后。它采用可变长度数组的形式,并且每个方法只有一个 params 参数。
当编译器尝试解析一个方法调用时,它查找其参数列表与调用的方法相匹配的方法。如果找不到可以与参数列表匹配的方法重载,但是存在与适当类型的 params 参数匹配的版本,则会调用该方法,并将额外的参数放在一个数组中。
下面的示例对此进行了演示:
using System; public class ParamsClass { public static void Main(string[] args) { Average ("List One", 5,10,15); Average ("List Two", 5,10,15,20,25,30); } public static void Average (string title, params int[] values) { int Sum = 0; Console.Write("Average of {0}: ", title); for (int i = 0; i < values.Length; i++) { Sum += values[i]; Console.Write(values[i] + ", "); } Console.WriteLine(": {0}", (float)Sum/values.Length); } }
在上面的示例中,用整型数组中的 params 参数声明了方法 Average,让我们使用任何数目的参数来调用它。输出结果如下:
Average of List One: 5, 10, 15, : 10 Average of List Two: 5, 10, 15, 20, 25, 30, : 17.5
注意,如果我们希望允许不同类型的不确定参数,我们可以指定 Object 类型的 params 参数。
查看本文来源如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。
现场直击|2021世界人工智能大会
直击5G创新地带,就在2021MWC上海
5G已至 转型当时——服务提供商如何把握转型的绝佳时机
寻找自己的Flag
华为开发者大会2020(Cloud)- 科技行者