c#的三個高級參數ref out 和Params 前言:在我們學習c#基礎的時候,我們會學習到c#的三個高級的參數,分別是out .ref 和Params,在這裡我們來分別的講解一下,在這裡的我們先不做具體的解釋,我會通過幾個例子來做分別的解釋。 一:out參數 1.首先我先給大家一個題:我們來寫一 ...
c#的三個高級參數ref out 和Params
前言:在我們學習c#基礎的時候,我們會學習到c#的三個高級的參數,分別是out .ref 和Params,在這裡我們來分別的講解一下,在這裡的我們先不做具體的解釋,我會通過幾個例子來做分別的解釋。
一:out參數
1.首先我先給大家一個題:我們來寫一個方法,來求一個數組中的最大值,最小值,總和,平均值。代碼如下:
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 };
通過分析我們會發現如果我們寫一個方法的時候,當我們需要返回值的時候,我們只能返回一個值,這個時候我們需要求最大值,最小值,總和和平均值。我們該如何的寫呢??假如我們沒有學習過out參數,這時候我們可以考慮返回一個數組,並且分別的假定數組中的元素的最大值,最小值,總和。(當總和求出來之後,平均值也就出來了)。詳細的代如下:
//我們聲明一個長度為4的數組,假設 res[0] 最大值 res[1]最小值 res[2]總和 res[3]平均值 int[] res = new int[4]; //假定數組中的第一個元素為最大值 res[0] = nums[0];//max //假定數組中的第二個元素為最小值 res[1] = nums[0];//min //假定數組中的第三個元素為總和 res[2] = 0;//sum
註:num[0]:這隻是我們假定的值。
2.這時候我們需要遍歷for迴圈,如果當前迴圈到的元素比我的最大值還要大,就把當前的元素賦值給我的最大值,如果當前迴圈到的元素比我的最小值還要小,就把當前的元素賦值給我的最小值,總和就是所有的元素相加,平均值為總和/數組的長度。詳細的代碼如下:
for (int i = 0; i < nums.Length; i++) { //如果當前迴圈到的元素比我假定的最大值還大 if (nums[i] > res[0]) { //將當前迴圈到的元素賦值給我的最大值 res[0] = nums[i]; } //如果當前迴圈到的元素比我的最小值還要小 if (nums[i] < res[1]) { //就把當前的元素賦值給我的最小值 res[1] = nums[i]; } //總和 res[2] += nums[i]; }
3.這時候直接返回數組就行了,完整的代碼如下:
1 /// <summary> 2 /// 計算一個數組的最大值、最小值、總和、平均值 3 /// </summary> 4 /// <param name="nums"></param> 5 /// <returns></returns> 6 public static int[] GetMaxMinSumAvg(int[] nums) 7 { 8 //我們聲明一個長度為4的數組,假設 res[0] 最大值 res[1]最小值 res[2]總和 res[3]平均值 9 int[] res = new int[4]; 10 //假定數組中的第一個元素為最大值 11 res[0] = nums[0];//max 12 //假定數組中的第二個元素為最小值 13 res[1] = nums[0];//min 14 //假定數組中的第三個元素為總和 15 res[2] = 0;//sum 16 for (int i = 0; i < nums.Length; i++) 17 { 18 //如果當前迴圈到的元素比我假定的最大值還大 19 if (nums[i] > res[0]) 20 { 21 //將當前迴圈到的元素賦值給我的最大值 22 res[0] = nums[i]; 23 } 24 //如果當前迴圈到的元素比我的最小值還要小 25 if (nums[i] < res[1]) 26 { 27 //就把當前的元素賦值給我的最小值 28 res[1] = nums[i]; 29 } 30 //總和 31 res[2] += nums[i]; 32 } 33 //平均值 34 res[3] = res[2] / nums.Length; 35 return res; 36 }
4.接下來就是在Main方法的中調用,截圖如下:
5.這時候我們需要考慮一個問題,我想要在數組中返回bool類型的值或者返回string類型的值,這時候我們怎麼辦呢??這時候需要我們的out參數登場了,out參數就側重於在一個方法中返回多個不同類型的值,但是它有一個重要的特點是:必須在方法的內部為其賦值。
(1).在我們需要返回的值的前面加out關鍵字。
(2).當我們在Main方法中調用我們的方法的時候,首先需要先聲明變數。
解題的思路跟上面的一樣這裡就不做過多的解釋了,直接完整的代碼奉上:
/// <summary> /// 計算一個整數數組的最大值、最小值、平均值、總和 /// </summary> /// <param name="nums">要求值得數組</param> /// <param name="max">多餘返回的最大值</param> /// <param name="min">多餘返回的最小值</param> /// <param name="sum">多餘返回的總和</param> /// <param name="avg">多餘返回的平均值</param> public static void Test(int[] nums, out int max, out int min, out int sum, out int avg) { //out參數要求在方法的內部必須為其賦值 //我們假設數組中的第一個元素為最大值 max = nums[0]; //假設數組中的第一個元素為最小值 min = nums[0]; //總和設置為零 sum = 0; for (int i = 0; i < nums.Length; i++) { if (nums[i] > max) { max = nums[i]; } if (nums[i] < min) { min = nums[i]; } sum += nums[i]; } avg = sum / nums.Length; }
1 static void Main(string[] args) 2 { 3 //寫一個方法 求一個數組中的最大值、最小值、總和、平均值 4 int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 5 //變數的聲明 6 int max1; 7 int min1; 8 int sum1; 9 int avg1; 10 //方法的調用 11 Test(numbers, out max1, out min1, out sum1, out avg1); 12 Console.WriteLine(max1); 13 Console.WriteLine(min1); 14 Console.WriteLine(sum1); 15 Console.WriteLine(avg1); 16 Console.ReadKey(); 17 18 }
調試的結果如下:
6.現在我麽用out參數做一個練習:分別的提示用戶輸入用戶名和密碼,寫一個方法來判斷用戶輸入的是否正確,返回給用戶一個登錄的結果,並且還要單獨的返回給用戶一個登錄的信息,如果用戶名錯誤,除了返回登錄結果之外,還要返回一個“用戶名錯誤”,如果密碼錯誤,除了返回登錄結果之外,還要返回一個“密碼錯誤”。
分析的思路:通過上面的題我們分析我們不僅要返回一個登錄結果,還要多餘的返回一個登錄的信息(是登錄名錯誤還是密碼錯誤還是未知的錯誤),這時候我們需要考慮使用out參數了。完整的代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _08使用out參數做登陸 { class Program { static void Main(string[] args) { Console.WriteLine("請輸入用戶名"); string userName = Console.ReadLine(); Console.WriteLine("請輸入密碼"); string userPwd = Console.ReadLine(); string msg; bool b = IsLogin(userName, userPwd, out msg); Console.WriteLine("登陸結果{0}",b); Console.WriteLine("登陸信息{0}",msg); Console.ReadKey(); } /// <summary> /// 判斷登陸是否成功 /// </summary> /// <param name="name">用戶名</param> /// <param name="pwd">密碼</param> /// <param name="msg">多餘返回的登陸信息</param> /// <returns>返回登陸結果</returns> public static bool IsLogin(string name, string pwd, out string msg) { if (name == "admin" && pwd == "888888") { msg = "登陸成功"; return true; } else if (name == "admin") { msg = "密碼錯誤"; return false; } else if (pwd == "888888") { msg = "用戶名錯誤"; return false; } else { msg = "未知錯誤"; return false; } } } }
結果如下截圖:
二:那麼接下來說一下ref參數的使用。
那麼老規矩我們首先來看一下這道題:使用方法來交換兩個int類型的變數。
思路分析:首先這個一道非常經典的面試題,我們可以使用兩種方法來做這道題(這裡不詳細的解釋)。
首先聲明一個方法來實現兩個int類型變數的交換。代碼如下:
1 /// <summary> 2 /// 交換兩個int類型的變數 3 /// </summary> 4 /// <param name="n1">第一個參數</param> 5 /// <param name="n2">第二個參數</param> 6 public static void Test(int n1, int n2) 7 { 8 n1 = n1 - n2;//-10 20 9 n2 = n1 + n2;//-10 10 10 n1 = n2 - n1;//20 10 11 }
在這個時候考慮我們在Main方法中調用就能實現結果嗎??答案是不行的。這就設計到我們的值類型和引用類型(在後面做詳細的解釋)。這個時候我們就要用到我們的ref參數了。這個時候我們給ref參數做一個定義:ref參數可以將一個變數帶入到一個方法中進行改變,改變完成後,在將改變完成後的值帶出方法。特點:ref參數要求在方法的外部必須為其賦值,在方法的內部可以不賦值。
完整的代碼如下:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _11_ref練習 { class Program { static void Main(string[] args) { //使用方法來交換兩個int類型的變數 //必須在方法的外部為其賦值 int n1 = 10; int n2 = 20; Test(ref n1, ref n2); Console.WriteLine(n1); Console.WriteLine(n2); Console.ReadKey(); } /// <summary> /// 交換兩個int類型的變數 /// </summary> /// <param name="n1">第一個參數</param> /// <param name="n2">第二個參數</param> public static void Test(ref int n1, ref int n2) { //方法的內部可以不賦值 n1 = n1 - n2;//-10 20 n2 = n1 + n2;//-10 10 n1 = n2 - n1;//20 10 } } }
代碼的結果截圖如下:
三:下麵我們來介紹一下Params可變參數。
這次我們的題目是:求任意長度的數字的和(整數類型的)。
我們直接給出定義:將實參列表跟可變參數類型一致的元素都當作數組中的元素來處理。特點:Params可變參數必須是形參列表中的最後一個元素。
直接看代碼:
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _12params可變參數 { class Program { static void Main(string[] args) { int sum = GetSum(8,9); Console.WriteLine(sum); Console.ReadKey(); } /// <summary> /// 求數組中的和 /// </summary> /// <param name="n">數組</param> /// <returns>返回總和</returns> public static int GetSum(params int[] n) { int sum = 0; for (int i = 0; i < n.Length; i++) { sum += n[i]; } return sum; } } }
大家看見了嗎,這時候我們將8 ,9 就當作我們形參列表數組中的元素來進行處理,這樣的話我們就是實現了我們的功能了。
四:這個時候我們該討論一下out參數和ref參數為什麼可以實現這樣的功能。比如拿ref參數做例子:
在討論這個問題之前我們該說一下值類型和引用類型的區別了。
(1):值類型和引用類型在記憶體中存儲的地方不一樣。
(2):在傳遞值類型和傳遞引用類型的時候,傳遞的方式不一樣,值類型我們稱之為值傳遞,引用類型我們稱之為引用傳遞。
值類型 :int double bool char decimal struct enum
引用類型:string 自定義類 數組 object 集合 介面
在舉例子之前首先請允許我說兩個重要的概念:
(1):值類型在複製的時候,傳遞的是這個值的本身。
(2):引用類型在複製的時候,傳遞的是對這個對象的引用。
首先我們先來句第一個例子,代碼如下:
//值傳遞和引用傳遞 int n1 = 10; int n2 = n1; n2 = 20; Console.WriteLine(n1); Console.WriteLine(n2); Console.ReadKey();
大家猜一下結果是多少??答案是:10 20,因為int是值類型,當我聲明int n1=10,就相當於我們在記憶體的棧中開闢了一塊記憶體地址,那我們如何在我們的記憶體中找到我們的值呢(也就是我們給這塊記憶體區域取一個名字,也就是我們的變數名),ok,當執行int n2=n1的時候,也就是進行了一個賦值的操作,如上所說,值類型在傳遞的時候我們傳遞的是值的本身。所以當我們執行完第二行的代碼的時候,n2=10,當執行完第三行的代碼的時候,又重新給n2賦值n2=20,所有輸出的結果就是:n1=10,n2=20。 畫圖表示如下:
接下來我們看第二個例子(Person預設是自定義類):
1 Person p1 = new Person(); 2 p1.Name = "張三"; 3 Person p2 = p1; 4 p2.Name = "李四"; 5 Console.WriteLine(p1.Name); 6 Console.ReadKey();
這個時候p1.Name為多少呢?? 答案是:李四。首先我們肯定是Person是自定義類,因為我們的自定義類為引用類型,所以在進行引用傳遞的時候傳遞的是對這個對象的引用(記憶體地址)。當我們聲明第一行的代碼的時候,會在記憶體的堆中開闢一塊區域存儲new Person();當為其Name賦值的時候,張三也存儲在堆中,這時候也會在棧中開闢一塊空間存儲了指向這塊區域的地址。所以當執行Person p2=p1,是把P1在棧中的引用複製了一份給了P2,所以現在他們兩指向的是堆中同一塊區域。所以當給Name重新賦值的時候,p1的值也會改變。截圖如下:
畫圖表示如下:
第三個例子:,代碼如下:
1 string s1 = "張三"; 2 string s2 = s1; 3 s2 = "李四"; 4 Console.WriteLine(s1); 5 Console.WriteLine(s2); 6 Console.ReadKey();
這個時候我們的s1和s2是多少呢??經過我的測試答案是:s1:張三,s2:李四。為什麼呢?要是按照我們上面的過程應該都是李四呀?因為我們的字元串是非常特殊的,正是由於字元串的不可變性,沒每當我們在為其賦值的時候都會在堆中重新開闢一塊區域進行存儲。所以兩塊區域沒有任何的關係。
思考的問題:這時候我們回顧在一個方法中實現交換變數的例子,當我們沒有用ref的時候,傳遞的是值的本身,當我們使用ref參數的時候傳遞的是這個對象的引用(記憶體地址)。所以我們總結出來ref的作用是:ref參數可以將一個值傳遞改變為引用傳遞。
好的,我們c#中的三個高級參數在這裡就介紹完了,如果大家有什麼疑問的話,可以留言,大家共同進步。
原文地址:http://www.cnblogs.com/MoRanQianXiao/p/7702587.html。