一、简介
任何一门编程语言都离不开函数,C# 中的函数(也可以称为方法)是一段具有签名(由函数名、参数类型和参数修饰符组成的函数信息)的代码块,可以用来实现特定的功能。
二、函数结构
一般情况下一个函数由以下几个部分组成:
- 访问权限修饰符:用于指定函数对一个类的可见性;
- 返回值类型:用于指定函数返回值的数据类型;
- 函数名称:用于进行函数调用的唯一名称;
- 参数列表:在调用函数时需要传递给函数的参数,参数列表是可选的,可以为空;
- 函数主体:其中包含了实现函数功能的若干代码。
实例代码:
// <访问修饰符> <返回值类型> <函数名称> (参数列表)
<Access Specifier> <Return Type> <Method Name>(Parameter List)
{
// 函数主体
Method Body
}
2.1 访问权限修饰符
所有类型和类型成员都具有可访问型级别。该级别可以控制是否可以从你的程序集或其他程序集中的其他代码中使用它们。简单来说就是当前函数或属性的访问权限。
- public 整个解决方案中访问。
- protected internal 是protected 和 internal 的并集,符合任意一条都可以访问。
- proteced 只允许在当前类内部以及该类的子类中访问。
- internal 只能在当前项目中访问。在同一个项目中与 public 的权限一致。
- private 只允许在本项目本类中被访问。
注意: (权限有小到大):private(字段、属性和方法的默认)
、protected
、internal(类的默认)
、protected internal
、public
;权限低的访问不了权限高的
2.2 返回值类型
定义当前函数返回值的类型,如果没有返回值可以设置为void
;
2.3 函数名称
函数名称与变量定义规则相同:
- 开头必须是字母或下划线,不能是数字。
- 字母是区分大小写的。
- 不可以是C语言关键字
2.4 参数列表
指定调用过程时它所需要的参数。 多个参数以逗号分隔。
2.5 函数主体
书写函数的主要执行代码内容。
三、函数调用
想要调用我们定义好的函数,首先需要将函数所在的类实例化为对象,然后通过对象.函数名()
的形式即可调用指定的函数,这里有几点需要注意:
- 若函数在定义时参数列表中定义了若干参数,那么在调用时也应该在函数名后面的括号中填入相应数量的参数,并且与参数列表中的参数类型一一对应;
- 若函数在定义时没有定义参数列表,那么在调用函数时也不需要在函数名后面填入参数;
- 对于有返回值的函数,在调用函数时可以使用一个变量(可选)来接收函数的返回值,变量的类型要与函数返回值的类型相同。
提示:若调用同一个类中静态函数(使用 static 修饰的函数),则可以省略实例化对象的过程,直接使用函数名()
的形式调用。
四、参数传递
在调用带有参数的函数时,需要将参数传递给函数。在介绍这几种传递方式之前,我们先来介绍一下形式参数(形参)和实际参数(实参)这两个概念:
- **形式参数:**在定义函数阶段参数列表中定义的参数称之为形式参数,简称形参,可以将它看作变量的名称,它没有具体的值,只是用来接收函数调用时传递过来的数据;
- **实际参数:**在函数被调用时传递给函数的参数称之为实际参数,简称实参,可以将它看作变量的值,用来为形参赋值。
参数可以通过三种方式传递给函数:
- 值传递: 值传递会复制参数的实际值并赋值给函数的形式参数,实参和形参使用的是两个不同内存位置中的值,当形参的值发生改变时,不会影响实参的值,从而保证了实参数据的安全。
- 引用传递: 引用传递会复制参数的内存位置并传递给形式参数,当形参的值发生改变时,同时也会改变实参的值。
- 输出传递: 输出传递可以一次返回多个值
4.1 值传递
在 C# 中,值传递是将参数传递给函数的默认方式,值传递的本质就是将实参的副本(将实参的值复制一份)传递给函数的形参。当调用函数时,将使用实参为每个形参赋值,并为每个形参创建一个新的存储位置,由于形参和实参指向不同的内存位置,所以无论是修改实参的值还是修改形参的值都不会对彼此造成影响。
class Demo {
static void Main(string[] args) {
int num = 11;
Console.WriteLine("调用函数之前:{0}", num);
Func(num);
Console.WriteLine("调用函数之后:{0}", num);
}
public static void Func(int val){
val += val;
Console.WriteLine("函数内部的值:{0}", val);
}
};
// 输出
// 调用函数之前:11
// 函数内部的值:22
// 调用函数之后:11
// 通过运行结果可以看出,尽管我们在函数内部对形参的值进行的修改,但是并不会影响函数外面实参 val 的值。
4.2 引用传递
引用传递是对变量内存位置的引用。与值传递不同,使用引用传递的形式传递参数时,并不会为形参创建新的内存地址,而是与实参共同指向相同的内存地址。正因为如此,当修改形参的值时,实参的值也会被修改。
在 C# 中,需要使用 ref 关键字来使用引用传递:
class Demo {
static void Main(string[] args) {
int num = 11;
Console.WriteLine("调用函数之前:{0}", num);
Func(ref num);
Console.WriteLine("调用函数之后:{0}", num);
}
public static void Func(ref int val){
val += val;
Console.WriteLine("函数内部的值:{0}", val);
}
};
// 输出
// 调用函数之前:11
// 函数内部的值:22
// 调用函数之后:22
// 通过运行结果可以看出,当函数内部值发生更改时,因为他们共用一个内存地址所以调用函数后值发出了改变
4.3 输出传递
使用 return 语句可以从函数中返回一个值,但是使用输出传递则可以从函数中一次性返回多个值。输出传递与引用传递相似,不同之处在于输出传递是将数据从函数中传输出来而不是传输到函数中。
在 C# 中,需要使用 out 关键字来使用输出传递
class Demo {
static void Main(string[] args) {
int num = 11;
Console.WriteLine("调用函数之前:{0}", num);
Func(out num);
Console.WriteLine("调用函数之后:{0}", num);
}
public static void Func(out int val){
val = 22;
}
};
// 输出
// 调用函数之前:11
// 调用函数之后:22
// 通过运行结果可以看出,在函数体内直接更改了nun的值
注意: 不可直接将参数进行运算,可以直接赋值。如果要进行算术运算则新建一个临时变量进行运算。
public static void Func(out int val){
// 语法错误
val += 22;
// 正确
int temp = 11;
val = temp;
val += val;
}