文章目录
- 五、方法与权限
- 访问权限
- 定义方法
- 参数传递
- 可变参数
五、方法与权限
Covers:方法和函数
访问权限
尽管还没有正式开始讲 C# 的类,但我们已经写过一个类 class Program 了,并且向其中添加了一个方法 static void Main。
C# 中一切都是对象,因此一切函数都是方法;方法就是封装在类或结构中的函数;封装就是把函数和数据打个包(这个包就是类或者结构);而言及封装就涉及到访问权限,因此我们需要先了解 C# 对访问权限的定义。
C# 中有 5 种访问权限:
-
private
:只有本类内可见,私有的; -
protected
:只有本类,以及从本类派生出的子类内可见; -
internal
:只在本程序集内可见,这包括了本类、本类在本程序及内派生出的子类、本程序集内其他类; -
protected internal
:在本程序集内,以及其它程序集中从本类派生出的子类中都可见; -
public
:在任何作用域中都可以访问,公有的。
这些访问权限都可以修饰方法或者属性,也可以修饰类本身,当指定一个类的访问权限时,就是指定该类对于其他类的可见性,类的访问权限默认是 internal 的。
定义方法
定义一个方法的语法是:ACCESS MODIFIER RET_TYPE METHOD(PARAMS) {BODY}
,这包含 5 个信息:
- 这是名为 METHOD 的方法;
- 其返回值的类型为 RET_TYPE(不返回任何值时为
void
); - 接受形参表 PARAMS 规定的参数(不接受参数时就省略);
- 该函数的访问权限是 ACCESS(可省略,默认为 private);
- MODIFIER 是额外的修饰符,如
static
(可省略,但目前我们编写的方法都需要这个修饰符); - 函数执行体为 BODY,用
return
关键字返回值,一旦程序抵达一个 return,后面的代码就不会继续执行。
参数传递
常常要向函数中传递参数,形参表规定了参数的类型、传入顺序和方式。传参方式有 3 种:值传参、引用传参 和 输出传参:
- 值传参:直接把调用处给出的参数拷贝一份传入,在方法执行体中修改传入的参数时对调用方不会产生任何影响,语法是
TYPE PARAM
,指定一个类型为 TYPE 的参数 PARAM,以值传递; - 引用传参:传入一个指向调用处所给实际参数变量的引用,在执行体中修改传入的参数时,会直接修改调用处的对应变量,行为与 C++ 一致,语法是
ref TYPE PARAM
,而且 在调用处,为这个形参传递的实参必须是变量,且变量名前面也要加上ref
关键字; - 输出传参:与引用传参类似,但实际参数可以是未初始化的,用于实现多返回值,语法是
out TYPE PARAM
,且变量名前面也要加上out
关键字
解释:有时我们希望方法返回多个值,那么在调用处就需要用额外的变量来接收这些值,C# 把这样的变量也作为参数用引用的形式传入,此时这些变量在调用前拥有的值是没有意义的,我们会想要用定义过而未初始化的变量来作为这样的参数。C# 中不存在先声明后定义,而将定义过(拥有内存资源)却未初始化的变量以引用传参传递给函数会造成安全问题,为解决这个矛盾,C# 提供了输出传参,这种形式传入的引用不需要初始化,在执行体中也不允许访问其原有值,但可以赋值给输出参数。
需要注意的是:
- 当方法直接接受数组名作为参数时,实质上这是值传参;但由于数组名本身就是引用,故也起到了引用传参所具有的“影响调用方”的效果,需要注意避免混淆。数组作参数按值传参的形参语法为
TYPE[] PARAM
,因为这是值传参,故实参直接传入数组名,不需要加 ref,这种情况下被调方能够修改数组中的内容,但 无法让数组名指向其它内存空间; - 还可以接受数组名的引用作为参数,这是真正的引用传参,传入了一个“引用的引用”,语法为
ref TYPE[] PARAM
,因为这是引用传参,故实参也要加 ref,这时 被调方不仅能够修改数组中的内容,还可以让数组名指向其它内存空间; - 参数可以有默认值,语法
TYPE PARAM = DEFAULT
,与 C++ 一样,所有有默认值的参数都需要位于没有默认值的参数之后。
值传参的例子:
using System;
namespace PassByValue
{
class SquarePrinter
{
public static void Print(uint width, uint height)
{
while (height != 0)
{
for (int i = 0; i < width; ++i)
{
Console.Write("*");
}
Console.WriteLine();
--height;
}
}
}
class Program
{
public static void Main()
{
SquarePrinter.Print(16, 8);
SquarePrinter.Print(8, 4);
SquarePrinter.Print(4, 2);
}
}
}
控制台输出:
****************
****************
****************
****************
****************
****************
****************
****************
********
********
********
********
****
****
引用传参的例子:
using System;
namespace PassByRef
{
class ArrayToy
{
public static void Modify(int[] array, uint pos, int data)
{
array[pos] = data;
}
public static void Swap(ref int[] l, ref int[] r)
{
int[] temp = l;
l = r;
r = temp;
}
}
class Program
{
static void Main()
{
int[] first = {1, 2, 3}, second = {4, 5, 6};
ArrayToy.Modify(first, 1, 0);
ArrayToy.Swap(ref first, ref second);
foreach (int i in first)
{
Console.Write(i + " ");
}
Console.WriteLine();
foreach (int i in second)
{
Console.Write(i + " ");
}
}
}
}
控制台输出:
4 5 6
1 0 3
输出传参的例子:
using System;
namespace OutputParams
{
class Program
{
static DateTime GetFullDate(out int year, out int month, out int day)
{
var now = DateTime.Now;
year = now.Year;
month = now.Month;
day = now.Day;
return now;
}
static void Main()
{
var time = GetFullDate(out int y, out int m, out int d);
Console.WriteLine("Today is {0}-{1}-{2}, {3}", y, m, d, time.DayOfWeek);
}
}
}
控制台输出:
Today is 2021-2-19, Friday
这里用到了 Console.WriteLine
的格式化输出,后面会介绍。
可变参数
为实现可变参数个数,可以用前面介绍的参数默认值,也可以用数组传递参数。之前认识过了 Main 方法的形参 string[] args
,这就是用数组传递可变参数的例子。
写一个例子来演示这个参数如何使用:
using System;
namespace AdvancedHello
{
class Program
{
static void Main(string[] args)
{
if (args.Length > 0)
{
Console.WriteLine("Hello, " + args[0] + "!");
}
else
{
Console.Write("What's your name? ");
string name = Console.ReadLine();
Console.WriteLine("Hello, " + name + "!");
}
Console.ReadKey();
}
}
}
用户通过命令行运行程序时,在命令之后可附带一系列用空格隔开的运行参数,如我们日常使用的 cd
命令,cd 是命令名(对于一个可执行文件),而空格后的路径就是传给它的运行参数。
Main 方法是程序的入口点,它本身的参数由程序之外传入,即用户传入的运行参数。C# 将用户传入的所有运行参按顺序放在 args 数组中,若没有任何运行参数,则 args 元素数为 0(与 C++ 不同,C++ 中运行参数数组一定至少有 1 个元素,该 0 号元素是程序的运行目录)。
上面的程序中我们判断传入的参数数组的元素数是否大于 0 来确定用户是否传入了参数,这种技巧在编写其他方法的可变形参表时也适用。
在 cmd 中 cd 到项目 exe 的构建目录中,并输入 exe 文件名称,加一个空格,输入一些字符串作为运行参数,执行即可看到效果:
...\bin\Debug>AdvancedHello.exe Bug
Hello, Bug!
...\bin\Debug>AdvancedHello.exe
What's your name? Bug
Hello, Bug!
T.B.C.