参数的运用
分类索引:C# 语言和运行时剖析--前言
参数的定义
一.可选参数与命名参数
- 可选参数: 可以为部分或者全部形参分配默认值. 然后,调用这些方法的代码可以选择不指定部分实参,接受其默认值.
- 命名参数:在使用可选参数时,可以通过制定参数名称的方法为其传递实参.
二.准则与规则
- 有默认值的参数必须放在没有默认值的所有参数之后。
- 默认值必须是编译时能确定的常量值。例如:基元类型;枚举类型;能设为null的引用类型等。但不能设置为对象的方法和属性等。
- 使用命名参数传递参数时,可以按照任何顺序。命名的实参传递必须放在实参列表的尾部,也就是,非命名参数应该放在命名参数之前。
- 如果形参标识了ref/out,命名实参应使用如下语法:
static void Main(string[] args) { //方法调用 Int32 a = 5; M(x: ref a); } //方法声明 private static void M(ref Int32 x) { }
三.代码实例:
class Program { private static Int32 n = 0; private static void M(Int32 x = 9, string s = "A", DateTime dt = default(DateTime), Guid guid = new Guid()) { Console.WriteLine("x={0}, s={1}, dt={2}, guid={3}", x, s, dt, guid); } static void Main(string[] args) { //全部调用初始值 M(); //x和s传入自定义实参,其他默认初始值 M(8, "X"); //使用默认实参与命名参数混合调用,命名参数可以不按照顺序,但必须在实参列表尾部 M(5, guid: Guid.NewGuid(), dt: DateTime.Now); //使用字段作为实参 M(n++, n++.ToString()); //使用命名参数并调用字段 M(s: n++.ToString(), x: n++); } }
参数的传递
一.传值与传递引用
- 传值调用: 默认情况下,CLR假设所有方法参数都是传值的,这分为两种情况:
- 参数是值类型: 调用者传入被调用方法内部的实参的值副本,分配在不同的线程栈空间,所以,在方法中对形参的修改对调用者不可见。
- 参数时引用类型:调用者传入被调用方法的是对象的地址值(相当于指针),所以,在方法内部对形参的修改对调用者可见。
但是,值得注意的是,这个规则对应String对象不适用,字符串在方法内部的改变对调用者也不可见。
- 传递引用:参数使用ref/out修饰时,表示以引用方式传递参数。以引用方式传递参数,不管参数是值类型还是引用类型,对调用者都可见。
二.传递可变数量的参数
- 应用场景:方法需要处理的参数数量不可预定,例如:连接任意数量的字符串。
- 使用方法:使用params关键字修饰参数数组。
- 使用优点:不用在调用方显示的将参数转换为数组,可以随意的传入参数,使代码更为优美,简洁。
三.实例代码
class Program { static Int32 Add(params Int32[] values) { Int32 sum = 0; foreach (int value in values) sum += value; return sum; } static void Main(string[] args) { Console.WriteLine(Add(1, 2, 3, 4, 5, 6)); } }
参数和返回类型的最佳实践
一.声明方法的参数类型
- 最佳实践
- 应尽量指定最弱的类型
- 在接口和基类的选择上,应尽量使用接口而不是基类。
- 优点说明:可以使方法应对更多的情况,而不是针对每一种参数进行不同的重载。
二.方法的返回参数类型
- 最佳实践:在不影响灵活性的情况下,应尽量返回一个最强的类型。
- 优点说明:更好的体现方法的功能,避免对调用方造成疑惑而产生调用不当的情况。