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.
全部測試用例源碼:

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