C#基础 [08] 方法 [下]

一、参数

 1.参数是什么?

    很多情况下,我们声明一个方法,就是为了它的返回值。这我们只需要在方法头中指定方法的返回类型,并且在方法体中使用return语句即可完成。但是,还有一些情况下,只通过这种方式是实现不了的。比如,需要将一些外部数据数据传入方法参与运算,或者需要多个返回值。这时,我们就需要一种称为“参数”的变量来充当这个传递员的角色。

    参数就是声明在方法头的参数列表中的特殊变量,它的作用就是为方法传入数据或将方法体中得到的结果传出方法。

  2.形参和实参

    1).形参

      形参就是声明在方法头的参数列表中的一种本地变量。它的声明和普通的本地变量一样,需要有类型和变量名;一个方法可以有任意数目的形参声明,多个形参声明之间用逗号分隔;除了output参数而外,参数在使用之前都要初始化为明确的值,否则方法就会报错。下面是一个带有两个形参列表的方法示例:

 1         /// <summary>
 2         /// 输出两数之和
 3         /// </summary>
 4         /// <param name="x">int类型的形参x</param>
 5         /// <param name="y">float类型形参y</param>
 6         public void PrintSum(int x, float y)
 7         {
 8             // 在方法体中,用实参初始化之后的形参的使用和本地变量一样
 9             float z = x + y;
10             Console.WriteLine("{0} + {1} = {2}", x, y, z);
11         }

    2).实参

      上面提到,调用一个带参数的方法时,形参的值必须在代码开始执行之前被初始化。这个用于初始化形参的变量或者表达式就称作实参(argument)。实参位于方法调用的参数列表中;每个实参的数据类型必须和声明它的形参的数据类型一致,或者可以隐式转换。下面是调用上一个方法传递实参的示例:

1             // 调用方法,传递实参。注意:实参必须是一个确定的值或者具有确定值的表达式
2             p.PrintSum(1, 2f);

  3.值参数

    值参数就是实参通过复制“实际值”到形参的方式把数据传递到方法体。值参数是默认的参数类型。当使用值参数调用方法时,系统做如下操作:第一步,在栈中为形参分配空间;第二步,复制实参的值到形参。下面是一个值参数的示例:

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var p = new Program();
 6             var a1 = new MyClass();
 7             var a2 = 10;
 8             // 方法调用:传实参,值参数的实参不一定是变量,可以是计算成相应类型值的表达式
 9             p.MyMethod(a1, a2 + 5);
10         }
11 
12         // 方法声明:声明形参
13         void MyMethod(MyClass f1, int f2)
14         {
15             f1.val += 5;
16             f2 += 5;
17         }
18     }
19 
20     class MyClass
21     {
22         public int val = 20;
23     }

   下图说明这一方法调用过程:

  

 4.引用参数

    引用参数就是一种实参复制引用地址到实参的参数。使用引用参数的方式:第一,在方法的声明和调用中都要使用ref修饰符;第二,实参必须是变量,而且在方法调用之前必须被赋值。引用参数的形参变量和实参变量指向相同的内存位置,在方法执行过程中对实参做的任何修改对形参都是可见的。

    下面的示例改写了MyMethod方法:

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var p = new Program();
 6             var a1 = new MyClass();
 7             var a2 = 10;
 8             // 方法调用:传实参,引用参数的实参必须是一个已赋值的变量
 9             // p.MyMethod(ref a1, ref a2 + 5); 错误,实参必须是一个已赋值的变量。
10             p.MyMethod(ref a1, ref a2);
11         }
12 
13         // 方法声明:使用ref关键字声明引用形参
14         void MyMethod(ref MyClass f1, ref int f2)
15         {
16             f1.val += 5;
17             f2 += 5;
18         }
19     }
20 
21     class MyClass
22     {
23         public int val = 20;
24     }

    下图说明上面方法调用过程:

  

  5.输出参数

    输出参数用于从方法体将数据传出到调用代码。输出参数的使用方式:第一,在声明和调用方法的时候都必须使用output修饰符;第二,实参必须是变量,该变量没有必要赋值,因为它会在方法体内部赋值,然后传出方法。int类型的TryPase方法就是一个使用输出参数的典型例子: public static bool TryParse(string s, out int result);

    下面是使用输出参数改写上面方法的示例:

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var p = new Program();
 6             MyClass a1 = null;
 7             int a2;
 8             // 方法调用:使用out修饰符传递实参          
 9             p.MyMethod(out a1, out a2);
10         }
11 
12         // 方法声明:使用out修饰符声明输出形参
13         void MyMethod(out MyClass f1, out int f2)
14         {
15             // 在方法体内部为输出参数赋值
16             f1 = new MyClass();
17             f1.val = 5;
18             f2 = 10;   
19         }
20     }
21 
22     class MyClass
23     {
24         public int val = 20;
25     }

    下图是该示例执行过程的说明:

  

  6.命名参数

    从参数的位置方面来讲,至此,我们使用的参数的每个形参和实参的位置都是一一对应的,这称为位置参数。位置参数是默认的参数形式。C#4.0中提出了命名参数的概念:命名参数在方法声明中的形参列表和位置参数一样,没有什么变化;在方法调用的时候,采用“形参名:实参值”的形式指定参数的名字,就可以以任意的顺序在方法调用的参数列表中列出实参。在方法调用中,可以将位置参数和命名参数混合使用,但所有位置参数必须在命名参数之前列出。 

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var p = new Program();
 6             MyClass a1 = new MyClass();
 7             int a2 = 10;
 8             // 方法调用:使用命名参数        
 9             p.MyMethod(f2: a2, f1: a1);
10 
11             // 方法调用:位置参数和命名参数混合使用,但是位置参数必须在命名参数之前。
12             p.MyMethod(a1, f2: a2);
13 
14         }
15 
16         // 方法声明:使用默认的位置参数
17         void MyMethod(MyClass f1, int f2)
18         {                     
19             f1.val += 5;
20             f2 += 10;
21         }
22     }
23 
24     class MyClass
25     {
26         public int val = 20;
27     }

  7.可选参数

    C#4.0引入了可选参数:就是在方法声明的时候使用初始化变量的方法为参数提供默认值,而在方法调用的时候,既可以包含该参数,也可以省略它。可选参数的使用条件:第一,可选参数的类型必须为值类型或者值为null的引用类型;第二,可选参数必须在所有必填参数之后,如果有params参数,必须在可选参数之后。下面是可选参数的示例:

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var p = new Program();
 6             MyClass a1 = new MyClass();
 7             int a2 = 10;
 8             // 方法调用:为可选参数f2提供显式值       
 9             p.MyMethod(a1, a2);
10 
11             // 方法调用:使用可选参数的默认值。
12             p.MyMethod(a1);
13 
14         }
15 
16         // 方法声明:为int类型的参数f2提供默认值
17         void MyMethod(MyClass f1, int f2 = 5)
18         {
19             f1.val += 5;
20             f2 += 10;
21         }
22     }
23 
24     class MyClass
25     {
26         public int val = 20;
27     }

  8.参数数组

    从参数的个数来讲,前面所列出的所有参数类型都是一个形参对应一个实参。而参数数组就是:零个或多个实参对应一个特殊的形参。参数数组的使用条件:

一个参数列表中只能有一个参数数组;如果有,它必须是参数列表中的最后一个参数。

    1).参数数组的声明方式:第一,在参数的数据类型前面使用params修饰符。第二,参数声明为数组变量。下面是一个使用参数数组声明的方法示例:

View Code
 1     class MyClass
 2     {
 3         // 使用参数数组声明一个方法
 4         public void ListInts(params int[] intVals)
 5         {
 6             if (intVals != null && intVals.Length > 0)
 7             {
 8                 foreach (var item in intVals)
 9                 {
10                     int x = item * 10;
11                     Console.WriteLine("X = {0} ", x);
12                 }
13             }
14         }
15     }

    2).带参数数组的方法的调用方式:

      有两种方式调用带参数数组的方法:第一种,使用一个用逗号表达式分隔的与参数类型相匹配的元素列表。第二种,使用一个与参数类型相匹配的元素的一维数组。下面是一个使用两种方式调用上面上面的带参数数组的方法的示例:

View Code
 1     class Program
 2     {
 3         static void Main(string[] args)
 4         {
 5             var a1 = new MyClass();            
 6             int x = 1, y = 2, z = 3;
 7             // 调用方式一:使用一个用逗号表达式分隔的int型元素的列表。
 8             a1.ListInts(x, y, z);
 9             Console.ReadKey();
10 
11             // 调用方式二:使用一个int类型元素的一维数组。
12             int[] arr = { 1, 2, 3 };
13             a1.ListInts(arr);
14             Console.ReadKey();
15         }
16     }

 二、方法重载

  1.什么是方法重载?

    方法重载就是在一个类中声明一个以上具有不同签名的同名方法。方法重载的目的:解决方法的重名问题,提高方法的可用性。

    方法签名的组成:方法名、参数类型、参数个数、参数顺序和参数的修饰符。注意:方法的返回值类型和方法的形参名称并不是方法签名的一部分。

  2.示例

    下面的类中声明了三个具有不同签名的同名方法,构成了方法重载。

View Code
 1     class MyClass
 2     {
 3         // 1.使用参数数组声明一个名为ListInts的方法
 4         public void ListInts(params int[] intVals)
 5         {
 6             if (intVals != null && intVals.Length > 0)
 7             {
 8                 foreach (var item in intVals)
 9                 {
10                     int x = item * 10;
11                     Console.WriteLine("X = {0} ", x);
12                 }
13             }
14         }
15 
16         // 2.重载1:声明了普通string数组类型的形参
17         public void ListInts(string[] vals)
18         {
19             string result = string.Empty;
20             foreach (var item in vals)
21             {
22                 result += item;
23             }
24             Console.WriteLine(result);
25         }
26 
27         // 重载2:声明了string类型形参
28         public string ListInts(string s)
29         {
30             return s + "......";
31         }
32 
33       }

三、递归

  方法递归就是方法自己调用自己。方法递归在为树绑定数据和无限级分类的设计当中用得比较多,是一种很优雅 解决方案。在现实生活中,有老和尚给小和尚讲故事的例子(从前有座山......),它就是一个典型的递归。

  下面是一个采用了递归的方式计算整数i的阶乘的方法:

View Code
 1         // 计算i的阶乘
 2         public int Factorial(int i)
 3         {
 4             if (i<=1)
 5             {
 6                 return i;
 7             }
 8             // 采用递归
 9             return i * Factorial(i - 1);
10         }

  

posted @ 2013-01-01 15:27  YunshiSun  阅读(425)  评论(0编辑  收藏  举报