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.");
            }
        }
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM