本文主要记录实际参数和形式参数的定义,以及 C# 中的形式参数的分类。
实际参数 argument 简称“实参”。
在调用有参方法时,方法名后面括号中的参数称为“实际参数”。
形式参数 parameter 简称“形参”。
在定义方法名和方法体的时候使用的参数称为“形式参数”,目的是用来接收调用该方法时传入的参数。
C# 中的形式参数 传值参数 传值参数会创建实参的副本来接收实参的值。
对形参的修改不影响实参的值。
参数类型为值类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Program { static void Main (string [] args ) { int value = 8 ; Method(value ); Console.WriteLine(value ); } static void Method (int value ) { value = 16 ; } }
参数类型为引用类型 创建新对象 :这种情况比较少见,一般不会用到。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Program { static void Main (string [] args ) { Student student = new Student() { Name = "daixx" }; Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); Method(student); Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); } static void Method (Student student ) { student = new Student() { Name = "daixxTech" }; } } class Student { public string Name { get ; set ; } }
不创建新对象,只操作对象 :这种情况也比较少见,因为作为方法而言,主要输出应该靠返回值,对形参所引用的对象进行操作属于方法的副作用(side-effect),这种副作用在平时编程时要尽量避免。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 class Program { static void Main (string [] args ) { Student student = new Student() { Name = "daixx" }; Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); Method(student); Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); } static void Method (Student student ) { student.Name = "daixxTech" ; } } class Student { public string Name { get ; set ; } }
引用参数 对形参的修改会影响实参的值。
在对应的形参和实参前面加 ref 关键字进行修饰。
参数类型为值类型 即有意利用方法的副作用来修改实参的值。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 class Program { static void Main (string [] args ) { int value = 8 ; Method(ref value ); Console.WriteLine(value ); } static void Method (ref int value ) { value = 16 ; } }
参数类型为引用类型 创建新对象
1 2 3 4 5 6 7 8 9 10 11 12 13 14 static void Main (string [] args ) { Student student = new Student() { Name = "daixx" }; Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); Method(ref student); Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); } static void Method (ref Student student ) { student = new Student() { Name = "daixxTech" }; }
不创建新对象,只操作对象 :与传值参数(即不加 ref 关键字)的结果相同,但是实现机理不同。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Program { static void Main (string [] args ) { Student student = new Student() { Name = "daixx" }; Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); Method(ref student); Console.WriteLine("{0}, {1}" , student.GetHashCode(), student.Name); } static void Method (ref Student student ) { student.Name = "daixxTech" ; } }
输出参数 对形参的修改会影响实参的值。
在对应的形参和实参前面加 out 关键字进行修饰。
方法体内必须要对输出参数进行赋值操作。
从语义上来讲,ref 是为了“改变”,out 是为了“输出”。
参数类型为值类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 class Program { static void Main (string [] args ) { int value = 8 ; if (IntParser.TryParse("abc" , out value )) { Console.WriteLine("Success, " + value ); } else { Console.WriteLine("Fail, " + value ); } if (IntParser.TryParse("16" , out value )) { Console.WriteLine("Success, " + value ); } else { Console.WriteLine("Fail, " + value ); } } } class IntParser { public static bool TryParse (string input, out int output ) { try { output = int .Parse(input); return true ; } catch { output = 0 ; return false ; } } }
参数类型为引用类型 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 class Program { static void Main (string [] args ) { Student student = null ; if (StudentFactory.Create("daixx" , 20 , out student)) { Console.WriteLine("{0}, {1}." , student.Name, student.Age); } } } class Student { public int Age { get ; set ; } public string Name { get ; set ; } } class StudentFactory { public static bool Create (string name, int age, out Student output ) { output = null ; if (string .IsNullOrEmpty(name)) { return false ; } if (age < 0 || age > 120 ) { return false ; } output = new Student() { Name = name, Age = age }; return true ; } }
数组参数 只能有一个,且必须是形参列表的最后一个,用 params 关键字进行修饰。
Console.WriteLine() 方法就是如此实现的。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Program { static void Main (string [] args ) { int sum = CalculateSum(1 , 2 , 3 ); Console.WriteLine(sum); } static int CalculateSum (params int [] intArray ) { int sum = 0 ; foreach (var item in intArray) { sum += item; } return sum; } }
具名参数 即参数具有名字。
具名参数的优点:
提高代码可读性
参数的位置不在受参数列表约束
1 2 3 4 5 6 7 8 9 10 11 12 13 class Program { static void Main (string [] args ) { PrintInfo("daixx" , 20 ); PrintInfo(age: 20 , name: "daixx" ); } static void PrintInfo (string name, int age ) { Console.WriteLine("{0}, {1}." , name, age); } }
可选参数 参数具有默认值,从而变为可选参数。
调用方法时不传入该参数,则该参数自动获得默认值。
不推荐使用可选参数。
1 2 3 4 5 6 7 8 9 10 11 12 class Program { static void Main (string [] args ) { PrintInfo(); } static void PrintInfo (string name = "daixx" , int age = 20 ) { Console.WriteLine("{0}, {1}." , name, age); } }
扩展方法(this 参数) 扩展方法必须是共有的,静态的,即被 public static 关键字进行修饰。
必须是形参列表的第一个,用 this 关键字进行修饰。
必须由一个静态类(一般命名为 SomeTypeExtension)来统一收纳对 SomeType 类型的扩展方法。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 class Program { static void Main (string [] args ) { double x = 3.14159 ; double y = x.Round(4 ); Console.WriteLine(y); } } static class DoubleExtension { public static double Round (this double input, int digits ) { return Math.Round(input, digits); } }
LINQ LINQ 就是扩展方法的一大应用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 using System.Linq; class Program { static void Main (string [] args ) { var myList = new List<int >() { 11 , 12 , 9 , 14 , 15 }; bool result = myList.All(i => i > 10 ); Console.WriteLine(result); } static bool AllGreaterThanTen (List<int > intList ) { foreach (var item in intList) { if (item <= 10 ) { return false ; } } return true ; } }