• C#方法解析


    C#4.0方法解析

    “方法”是包含一系列语句的代码块。 程序通过“调用”方法并指定所需的任何方法参数来执行语句。 在 C# 中,每个执行指令 都是在方法的上下文中执行的。

    最近在写一个反射调用时,需要通过反射来调用方法。想写一个通用的方法调用的通用函数,这就需要将方法各种形式考虑在内。
    在这里只是对C#4.0的方法进行一次简单总结,也希望给大家一个清晰的认识。

    方法模板:可访问性  修饰符  返回值  方法名(参数列表){...}

    可访问性: private protected internal public
    
    方法修饰符: static abstract virtual/override 等
    
    返回值: 某种类型或无返回值
    
    方法名:methodname
    
    参数列表:这个有多种情况
    

    其实C#4.0中的方法,除了常见的方法,还有几种比较特殊的方法。

    (1)属性,其实属性的get和set生成了两个单独方法
    (2)索引,我们平时用的很多,this["code"]等,其实在CLR中,也生成了get_Item 与set_Item两个方法。我们获取索引时,就可以用这个两个方法名 + 参数列表,获得相应的索引。
    (3)泛型方法,如: T CreateInstance<T>(){...}

    但是这些都可以通过一定的 规律转为通常方法来处理。但在写反射的时候一定要分析到这类问题。

    因为方法签名的其他部分比较简单,这里只是针对方法的参数列表进行展开讨论。

    参数有多种:普通的也不赘述,如:void Do(string Msg){};  这里只是讲述几种特殊的参数。

    1、ref/out

    如果不使用ref/out,则传递的只是这些值的Copy.传递的是引用类型的地址值,则将传递引用类型的地址值的一个Copy,实际上就是新开一个不同的内存变量来存储这个地址值的拷贝。而是用ref/out,传递的还是引用类型的地址值,但是传递的是原来的哪个引用类型的地址值。

    ref

    ref 关键字使参数按引用传递。其效果是,当控制权传递回调用方法时,在方法中对参数所做的任何更改都将反映在该变量中。若要使用 ref 参数,则方法定义和调用方法都必须显式使用 ref 关键字。

    例子:

            /// <summary>
            /// ref测试
            /// </summary>
            /// <param name="count"></param>
            static void RefTest(ref int count)
            {
                count += 10;
                Console.WriteLine("In method count: {0}",count);
            }

    调用结果:

                //ref
                int count = 10;
                Console.WriteLine("Before calling method the count is : {0}", count);//输出:After calling  method the count is : 10
                RefTest(ref count);
                Console.WriteLine("After calling  method the count is : {0}", count);//输出:After calling  method the count is : 20

    传递到 ref 参数的参数必须最先初始化。这与 out 不同,out 的参数在传递之前不需要显式初始化。

    out

    out 关键字会导致参数通过引用来传递。这与 ref 关键字类似,不同之处在于 ref 要求变量必须在传递之前进行初始化。若要使用 out 参数,方法定义和调用方法都必须显式使用 out 关键字。例如:
    例子:

            /// <summary>
            /// out测试
            /// </summary>
            /// <param name="count"></param>
            static void OutTest(out int count)
            {
                //count += 10;//这样写,编译报错:使用了未赋值的参数"count"
                count = 10;
                Console.WriteLine("In method count: {0}", count);
            }

    调用:

                //out
                int count2;
                OutTest(out count2);
                Console.WriteLine("After calling  method the count is : {0}", count2);//输出:After calling  method the count is : 10

     注意情况:

    ref 和 out 关键字在运行时的处理方式不同,但在编译时的处理方式相同。

    因此,如果一个方法采用 ref 参数,而另一个方法采用 out 参数,则无法重载这两个方法。

    例如,从编译的角度来看,以下代码中的两个方法是完全相同的,因此将不会编译以下代码:

    class CS0663_Example 
    {
        public void SampleMethod(out int i) {  }
        public void SampleMethod(ref int i) {  }
    }

    但是,如果一个方法采用 ref 或 out 参数,而另一个方法不采用这两类参数,则可以进行重载,如下所示
    class RefOutOverloadExample
    {
        public void SampleMethod(int i) {  }
        public void SampleMethod(out int i) {  }
    }

    当希望方法返回多个值时,声明 out 方法很有用
    在函数中,所有out引用的变量都要赋值,ref引用的可以修改,也可以不修改。 

    2、params --可变参数

    params 关键字可以指定在参数数目可变处采用参数的方法参数。
    在方法声明中的 params 关键字之后不允许任何其他参数,并且在方法声明中只允许一个 params 关键字。

    例子:

            /// <summary>
            /// 测试Params关键字
            /// </summary>
            /// <param name="msgList"></param>
            static void ParamsTest(params string[] msgList)
            {
                foreach (string item in msgList)
                {
                    Console.WriteLine(item);
                }
            }

    调用

                //测试可变参数
                ParamsTest();
                ParamsTest("Hello!","GoodBye!");
                //输出:
                //Hello!
                //GoodBye!
                ParamsTest("吃了吗?", "吃了!","回见!");
                //输出:
                //吃了吗?
                //吃了!
                //回见!

    3、可选参数

    可以指定过程参数是可选的,并且在调用过程时不必为其提供变量。遵循以下规则:

        (1)过程定义中的每个可选参数都必须指定默认值。

        (2)可选参数的默认值必须是一个常数表达式。

        (3)过程定义中跟在可选参数后的每个参数也都必须是可选的。

    例子:

            /// <summary>
            /// 可选参数
            /// </summary>
            /// <param name="name"></param>
            /// <param name="isMan"></param>
            static void OptionalTest(string name, bool isMan = true)
            {
                if (isMan)
                {
                    Console.WriteLine(name + " is a boy.");
                }
                else
                {
                    Console.WriteLine(name + " is a girl."); 
                }
            }

    调用结果:

                //可选参数
                OptionalTest("Tom"); //输出: Tom is a boy.
                OptionalTest("Lucy",false); //输出:Lucy is a girl

    4.命名参数

    名称2:参数值2…

    命名参数让我们可以在调用方法时指定参数名字来给参数赋值,这种情况下可以忽略参数的顺序。在方法参数很多的情况下很有意义,可以增加代码的可读性。

    如下方法声明:

            /// <summary>
            /// 通常方法
            /// </summary>
            /// <param name="name">名字</param>
            /// <param name="age">年龄</param>
            static void Common(string name,int age)
            {
                Console.WriteLine("The age of " + name + " is " + age + ".");
            }

    我们可以这样来调用上面声明的方法    

                //通用方法
                Common("Jim", 20); //输出:The age of Jim is 20.
    
                //命名参数,跟参数顺序无关
                Common(name: "Tom", age: 21); //输出:The age of Tom is 21.
                Common(age: 21, name: "Tom"); //输出:The age of Tom is 21.

    全部测试用例源码

    View Code
    using System;
    
    namespace MethodAnalysis
    {
        class Program
        {
            static void Main(string[] args)
            {
                //通用方法
                Common("Jim", 20); //输出:The age of Jim is 20.
    
    
                //命名参数,跟参数顺序无关
                Common(name: "Tom", age: 21); //输出:The age of Tom is 21.
                Common(age: 21, name: "Tom"); //输出:The age of Tom is 21.
    
    
                //ref
                int count = 10;
                Console.WriteLine("Before calling method the count is : {0}", count);//输出:After calling  method the count is : 10
                RefTest(ref count);
                Console.WriteLine("After calling  method the count is : {0}", count);//输出:After calling  method the count is : 20
                            
                //out
                int count2;
                OutTest(out count2);
                Console.WriteLine("After calling  method the count is : {0}", count2);//输出:After calling  method the count is : 10          
    
                //测试可变参数
                ParamsTest();
                ParamsTest("Hello!","GoodBye!");
                //输出:
                //Hello!
                //GoodBye!
                ParamsTest("吃了吗?", "吃了!","回见!");
                //输出:
                //吃了吗?
                //吃了!
                //回见!
    
    
                //可选参数
                OptionalTest("Tom"); //输出: Tom is a boy.
                OptionalTest("Lucy",false); //输出:Lucy is a girl.
    
    
                Console.WriteLine("点击任意键退出");
                Console.ReadKey();
            }
    
            /// <summary>
            /// 通常方法
            /// </summary>
            /// <param name="name">名字</param>
            /// <param name="age">年龄</param>
            static void Common(string name,int age)
            {
                Console.WriteLine("The age of " + name + " is " + age + ".");
            }
    
            /// <summary>
            /// ref测试
            /// </summary>
            /// <param name="count"></param>
            static void RefTest(ref int count)
            {
                count += 10;
                Console.WriteLine("In method count: {0}",count);
            }
            /// <summary>
            /// 交换字符串
            /// 如果不没有使用ref,两个字符串的值是不能互换的
            /// </summary>
            /// <param name="s1"></param>
            /// <param name="s2"></param>
            static void SwapStrings(ref string s1, ref string s2)
            {
                string temp = s1;
                s1 = s2;
                s2 = temp;
                System.Console.WriteLine("Inside the method: {0} {1}", s1, s2);
            }
    
            /// <summary>
            /// out测试
            /// </summary>
            /// <param name="count"></param>
            static void OutTest(out int count)
            {
                //count += 10;//这样写,编译报错:使用了未赋值的参数"count"
                count = 10;
                Console.WriteLine("In method count: {0}", count);
            }
    
            /// <summary>
            /// 测试Params关键字
            /// </summary>
            /// <param name="msgList"></param>
            static void ParamsTest(params string[] msgList)
            {
                foreach (string item in msgList)
                {
                    Console.WriteLine(item);
                }
            }
    
            /// <summary>
            /// 可选参数
            /// </summary>
            /// <param name="name"></param>
            /// <param name="isMan"></param>
            static void OptionalTest(string name, bool isMan = true)
            {
                if (isMan)
                {
                    Console.WriteLine(name + " is a boy.");
                }
                else
                {
                    Console.WriteLine(name + " is a girl."); 
                }
            }
    
    
            /// <summary>
            /// 可选参数
            /// 可选参数,后面只能是可选参数
            /// </summary>
            /// <param name="name"></param>
            /// <param name="isMan"></param>
            /// <param name="toys"></param>
            static void OptionalTest(string name, bool isMan = true, params string[] toys)
            {
                if (isMan)
                {
                    Console.WriteLine(name + " is a boy.");
                }
                else
                {
                    Console.WriteLine(name + " is a girl.");
                }
            }
        }
    }
  • 相关阅读:
    结合自己造的轮子实践按需加载
    清风不知道--项目需求分析
    2020软件工程作业——团队03
    2020软件工程作业——团队02
    清风不知道——团队展示
    Java注解
    Java反射机制
    浅谈Vector
    浅谈LinkedList
    在IDEA中搭建Java源码学习环境并上传到GitHub上
  • 原文地址:https://www.cnblogs.com/yank/p/2663793.html
Copyright © 2020-2023  润新知