Unity C# 爆破计划(五):方法与权限

15 篇文章 1 订阅


五、方法与权限

Covers:方法和函数

访问权限

尽管还没有正式开始讲 C# 的类,但我们已经写过一个类 class Program 了,并且向其中添加了一个方法 static void Main。

C# 中一切都是对象,因此一切函数都是方法;方法就是封装在类或结构中的函数;封装就是把函数和数据打个包(这个包就是类或者结构);而言及封装就涉及到访问权限,因此我们需要先了解 C# 对访问权限的定义。

C# 中有 5 种访问权限:

  1. private:只有本类内可见,私有的;
  2. protected:只有本类,以及从本类派生出的子类内可见;
  3. internal:只在本程序集内可见,这包括了本类、本类在本程序及内派生出的子类、本程序集内其他类;
  4. protected internal:在本程序集内,以及其它程序集中从本类派生出的子类中都可见;
  5. 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.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值