当前位置: 首页 > news >正文

C#学习笔记(五)——函数

一、定义和使用函数。

       直接通过例子进行说明吧

class Program
    {
        static void Write()
        {
            Console.WriteLine("Test output from function");
        }

        static void Main(string[] args)
        {
            Write();
            Console.ReadKey();
        }
    }

1、函数的构架

(1)关键字:static 和 void

          static与面向对象的思维有关系,我们在这里先默认每个函数都需要加上这个关键字;

          void即使便是返回值为空的意思。、

(2)函数名后跟圆括号  e.g  Write();

(3)圆括号里面可以有参数,这个放在后面再讨论,

(4)一个要执行的代码块,放在花括号里面。

 

2、返回值

(1)当函数返回一个值时,可以采用以下两种方式修改函数

a、在函数声明中指定返回值得类型,但不使用关键字void;

b、使用return关键字结束函数的执行,把返回值传送给调用代码。

static <returnType> <functionName>()
{
      ……
      return <returnValue>;
}

(2)return 不一定要放在最后一行,也很经常用于直接跳出函数。

 

3、参数

(1)当函数接受参数的时候,就必须指定下列内容

a、函数在其定义指定接受的参数列表,以及这些参数的类型;

b、在每个函数调用中匹配的参数列表。

c、其中可以有任意多个参数,每个参数都有一个类型和一个名称,参数用逗号隔开。每个参数都在函数的代码中用作一个变量。

(2)一个demo

namespace Exercise
{
    class Program
    {
        static int MaxValue(int[] intArray)
        {
            int maxVal = intArray[0];
            for(int i=1;i<intArray.Length;i++)
            {
                if(intArray[i]>maxVal)
                {
                    maxVal = intArray[i];
                }
            }
            return maxVal;
        }

        static void Main(string[] args)
        {
            int[] myArray = { 1, 5, 7, 99, 7, 8, 9, 3 };
            int maxVal = MaxValue(myArray);
            Console.WriteLine("The maximum value in myArray is {0}", maxVal);
            Console.ReadKey();
        }
    }
}

运行结果是:

image

(3)参数匹配

        在调用函数时,必须使参数与函数定义中指定的参数完全匹配,这意味着要匹配参数的类型、个数和顺序。当然这样子会导致我们重复写同样的代码,仅仅是因为参数类型的小改变,但是后面我们会有传说中的重载函数来解决这个问题。

(4)参数数组

        C#允许定义一个(只能指定一个)特定的参数,这个参数必须是函数定义中参数列表的最后一个,称之为参数数组。参数数组可以使用个数不定的参数调用函数,规定用关键字params关键字定义。

        一个demo:

namespace Exercise
{
    class Program
    {
        static int SumVals(params int[] vals)
        {
            int sum = 0;
            foreach (int val in vals)
            {
                sum += val;
            }
            return sum;
        }
        static void Main(string[] args)
        {
            int sum = SumVals(1, 5, 7, 9, 05, 4, 8, 0, 6, 4);
            Console.WriteLine(sum);
            Console.ReadKey();
        }
    }
}

(5)引用参数和值参数

image

然后我们调用这个函数

image

我们会发现,我们对参数进行的double操作并不会影响Main()中的值

        但是我们在这里有一个引用的方法,可以讲参数和引入变量绑定在一起,也就是说参数成为了引入变量的一个别名,实际上是一样的东东,方法就是使用ref关键字进行指定才参数。

        然后在函数调用中我们需要再一次指定ref参数,demo如下

class Program
    {
        static void ShowDouble(ref int val)
        {
            val *= 2;
            Console.WriteLine("val doubled = {0}",val);
        }
        static void Main(string[] args)
        {
            int myNumeber = 5;
            Console.WriteLine("myNumber = {0}", myNumeber);
            ShowDouble(ref myNumeber);
            Console.WriteLine("myNumber = {0}", myNumeber);
            
        }
    }

Attention:C#不允许假定ref参数在使用它的函数中初始化,也就是说调用的参数一定要有赋值过。

 

(6)输出参数

       除了按引用传递值之外,还可以使用out关键字,指定所给的的参数是一个输出参数,out关键字和ref关键字的使用方法相同,执行的原理与引用参数一样,但是有一些重要的区别:

a、把未赋值的变量用作ref参数是非法的,但可以把未赋值的变量作out参数。

b、另外,在函数使用out参数时,out参数必须看成未赋值。换句话说,out参数会遗忘原有的数值。

现在写一个demo

class Program
    {
        static int MaxValue(int[] intArray,out int maxIndex)
        {
            int maxVal = intArray[0];
            maxIndex = 0;
            for(int i=1;i<intArray.Length;i++)
            {
                if(intArray[i]>maxVal)
                {
                    maxVal = intArray[i];
                    maxIndex = i;
                }
            }
            return maxVal;
        }
        static void Main(string[] args)
        {
            int[] myArray = {3,5,6,77,4,24,234,26,536,7,6577,8};
            int maxIndex;
            Console.WriteLine("The maximum value in myArray is {0}",MaxValue(myArray,out maxIndex));
            Console.WriteLine("The first occurrence of this value is at element {0}",maxIndex);
            Console.ReadKey();
        }
    }

 

二、变量的作用域

1、变量的作用域包含定义他们的代码块和直接嵌套在其中的代码块。(包括循环和条件语句)

namespace Exercise
{
    class Program
    {
        
        static void Main(string[] args)
        {
            int i;
            for(i=0;i<10;i++)
            {
                string text = "Line" + Convert.ToString(i);
                Console.WriteLine("{0}", text);
            }
            Console.WriteLine("Last text output in loop: {0}", text);
        }
    }
}

       由于text是循环里的局部变量,所以跳出循环之后就不能在使用text了。然后修改一下

class Program
    {
        
        static void Main(string[] args)
        {
            int i;
            string text;
            for(i=0;i<10;i++)
            {
                text = "Line" + Convert.ToString(i);
                Console.WriteLine("{0}", text);
            }
            Console.WriteLine("Last text output in loop: {0}", text);
        }
    }

          这段代码依旧会是编译出错,原因是必须在使用变量前对其进行声明和初始化,而text是在for循环里面初始化的,赋给text的值在循环快退出时就丢失了,但是还可以进行如下的修改

class Program
    {
        
        static void Main(string[] args)
        {
            int i;
            string text="";
            for(i=0;i<10;i++)
            {
                text = "Line" + Convert.ToString(i);
                Console.WriteLine("{0}", text);
            }
            Console.WriteLine("Last text output in loop: {0}", text);
        }
    }

           这次代码就是先在循环外进行了初始化。所以在这里我们需要掌握一个好的习惯就是在声明一个变量的时候最好是记得进行初始化,这样的话即使出错,我们也可以很容易的得知是那个变量出现了问题,还有就是避免这些问题的发生,

 

2、全局变量

            这钟变量最好是少使用,一般我们也是很少进行使用的,尽量的进行避免。但是如果全局都需要经常访问的话,全局变量的优势就会体现出来。

            在局部变量和全局变量的名字发生冲突的时候,局部变量会掩盖全局变量。

 

三、Main()函数

       Main()是C#应用程序的入口和出口。就是说Main()函数是整个函数的框架。

1、Main()的四种形式

image

(1)第三四种版本会返回一个int值,他们可以用于表示程序如何终止,通常作为一种错误提示,如果是正常关闭的话,就是返回0。

(2)Main()的可选参数args是从应用程序的外部接受信息的方法,这些信息在运行期间指定,其形式是命令行参数。也就是说在执行控制台应用程序时,指定的任何命令参数都放在这个args数组中,然后可以根据需要在Main()中使用这些参数。

         然后这里有个简单的demo

namespace Exercise
{
    class Program
    {
        
        static void Main(string[] args)
        {
            Console.WriteLine("{0} command line argument were specified:", args.Length);
            foreach(string arg in args)
            {
                Console.WriteLine(arg);
            }
            Console.ReadKey();
        }
    }
}

         然后我们要在项目属性中进行设置,如图(在调试那一栏)

image

       在命令参数行:我们可以加入很多的命令- -,在这里就随意加一点,只是实现这个功能而已,如果单词和单词之间有空格存在的话,我们就需要用“”括起来,这样子才不会被当成是多个命令。效果如图

image

 

四、结构函数

          就是结构体中可以不仅仅可以加入变量,而且可以加入函数。那么我们就用一个demo来解决吧。

namespace Exercise
{
    class Program
    {
        struct customerName
        {
            public string firstName, lastName;

            public string Name()
            {
                return firstName + " " + lastName;
            }
        }

        static void Main(string[] args)
        {
            customerName myCustomerName;
            myCustomerName.firstName = "Chen";
            myCustomerName.lastName = "Xuewen";
            Console.WriteLine("{0}", myCustomerName.Name());
            Console.ReadKey();
        }
    }
}

           然后函数的可以在结构体内可以看做是全局函数。

 

五、函数的重载

          重载就是“重复”,函数的重载也就是说函数可以有同样的名字,但是有着不同的功能,比如说如果我们要求一个数组里面的最大值,但是数组又有不同的类型,如果再取不同 的名字会很麻烦,于是哦我们就可以使用函数重载,保持函数名称不变,而实现功能。现在有个demo、

static int MaxValue(int[] intArray)
        {
            int maxVal = intArray[0];
            for(int i=0;i<intArray.Length;i++)
            {
                if(intArray[i]>maxVal)
                {
                    maxVal = intArray[i];
                }
            }
            return maxVal;
        }

        static double MaxValue(double[] doubleArray)
        {
            double maxVal = doubleArray[0];
            for (int i = 0; i < doubleArray.Length; i++)
            {
                if (doubleArray[i] > maxVal)
                {
                    maxVal = doubleArray[i];
                }
            }
            return maxVal;
        }

        这两个函数就实现了函数的重载,但请注意,如果仅仅只是改变return(也就是返回值的类型)的类型,C#是不会认为是2个重载的函数,而是会发生错误。大家要小心

 

六、委托

        委托的声明非常类似于函数,但是不带函数体,但是要使用delegate关键字,委托声明指定了一个返回类型和一个参数列表。

        在定义了委托后,就可以声明该委托类型的变量,接着把这个变量初始化为与委托有相同返回类型和桉树列表的函数引用。之后就可以使用这个委托来调用这个函数,就像这个变量就是一个函数的样子。

namespace Exercise
{
    class Program
    {
        delegate double ProcessDelegate(double param1, double param2);
      //设置一个委托

        static double Mulitiply(double param1, double param2)
        {
            return param1 * param2;
        }

        static double Division(double param1,double param2)
        {
            return param1 / param2;
        }

        static void Main(string[] args)
        {
            ProcessDelegate process;//声明一个委托(但是还没有绑定函数)

       //下面这段代码就是用来分割出来两个数字的- -,比C++麻烦很多- - 
            Console.WriteLine("Enter 2 number separated with a comma:");
            string input = Console.ReadLine();
            int commaPos = input.IndexOf(",");
            double param1 = Convert.ToDouble(input.Substring(0, commaPos));
            double param2 = Convert.ToDouble(input.Substring(commaPos + 1, input.Length - commaPos - 1));
            
      //选择功能
          Console.WriteLine("Enter M to multiply or D  to divide:");
            input = Console.ReadLine();
            input = input.ToUpper();
            if(input == "M")
            {
                process = new ProcessDelegate(Mulitiply);
            }
            else
            {
                process = new ProcessDelegate(Division);
            }
            Console.WriteLine("Result:{0}", process(param1, param2));


            Console.ReadKey();
        }
    }
}

          然后委托主要是用于事件,这个在第13章中会用到哈。

相关文章:

  • Google CEO 定义 Web 3.0
  • 判断字符串是否是回文字符串或者是否含有回文字符子串 (我是从两颗番茄的博客看的题目,然后自己编的) 不断学习!!...
  • DICOMDIR结构
  • MVC2 Area实现网站多级目录
  • IBM Java多线程 - 4.共享对数据的访问
  • TADOQuery池
  • Windows7问题集
  • 连接postgres特别消耗cpu资源而引发的PostgreSQL性能优化考虑
  • 应用开发框架之——业务规则脚本化
  • 对等计算实践: P2P 遇上 SSL
  • Sprout and the Bean
  • 数据库水平拆分和垂直拆分区别(以mysql为例)
  • 跟我一起学WCF(11)——WCF中队列服务详解
  • 第6期(江西省吉安市永丰县)县长手机信箱工作简报(自吹自擂政绩,自圆其说)
  • 各种排序算法的稳定性和时间复杂度小结
  • “寒冬”下的金三银四跳槽季来了,帮你客观分析一下局面
  • 《深入 React 技术栈》
  • C++回声服务器_9-epoll边缘触发模式版本服务器
  • GraphQL学习过程应该是这样的
  • java8 Stream Pipelines 浅析
  • JavaScript 基本功--面试宝典
  • mockjs让前端开发独立于后端
  • socket.io+express实现聊天室的思考(三)
  • Web设计流程优化:网页效果图设计新思路
  • 初探 Vue 生命周期和钩子函数
  • 搞机器学习要哪些技能
  • 如何优雅地使用 Sublime Text
  • 限制Java线程池运行线程以及等待线程数量的策略
  • 深度学习之轻量级神经网络在TWS蓝牙音频处理器上的部署
  • 哈罗单车融资几十亿元,蚂蚁金服与春华资本加持 ...
  • ​DB-Engines 12月数据库排名: PostgreSQL有望获得「2020年度数据库」荣誉?
  • ​LeetCode解法汇总307. 区域和检索 - 数组可修改
  • ​力扣解法汇总1802. 有界数组中指定下标处的最大值
  • ​虚拟化系列介绍(十)
  • # 数论-逆元
  • ###C语言程序设计-----C语言学习(6)#
  • #宝哥教你#查看jquery绑定的事件函数
  • (07)Hive——窗口函数详解
  • (pojstep1.1.1)poj 1298(直叙式模拟)
  • (二)换源+apt-get基础配置+搜狗拼音
  • (附源码)计算机毕业设计SSM疫情社区管理系统
  • (离散数学)逻辑连接词
  • (力扣)循环队列的实现与详解(C语言)
  • (最简单,详细,直接上手)uniapp/vue中英文多语言切换
  • . Flume面试题
  • .NET 8 编写 LiteDB vs SQLite 数据库 CRUD 接口性能测试(准备篇)
  • .net framework4与其client profile版本的区别
  • .NET性能优化(文摘)
  • .NET与 java通用的3DES加密解密方法
  • .Net中间语言BeforeFieldInit
  • .NET中两种OCR方式对比
  • [ vulhub漏洞复现篇 ] struts2远程代码执行漏洞 S2-005 (CVE-2010-1870)
  • [ 数据结构 - C++]红黑树RBTree
  • [2016.7 Day.4] T1 游戏 [正解:二分图 偏解:奇葩贪心+模拟?(不知如何称呼不过居然比std还快)]
  • [20180312]进程管理其中的SQL Server进程占用内存远远大于SQL server内部统计出来的内存...