c#的三個高級參數ref out 和Params
前言:在咱們學習c#基礎的時候,咱們會學習到c#的三個高級的參數,分別是out .ref 和Params,在這裏咱們來分別的講解一下,在這裏的咱們先不作具體的解釋,我會經過幾個例子來作分別的解釋。html
一:out參數面試
1.首先我先給你們一個題:咱們來寫一個方法,來求一個數組中的最大值,最小值,總和,平均值。代碼以下:sql
int[] numbers = { 1, 2, 3, 4, 5, 6, 7, 8, 9 }; 數據庫
經過分析咱們會發現若是咱們寫一個方法的時候,當咱們須要返回值的時候,咱們只能返回一個值,這個時候咱們須要求最大值,最小值,總和和平均值。咱們該如何的寫呢??假如咱們沒有學習過out參數,這時候咱們能夠考慮返回一個數組,而且分別的假定數組中的元素的最大值,最小值,總和。(當總和求出來以後,平均值也就出來了)。詳細的代以下:express
//咱們聲明一個長度爲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]:這只是咱們假定的值。c#
2.這時候咱們須要遍歷for循環,若是當前循環到的元素比個人最大值還要大,就把當前的元素賦值給個人最大值,若是當前循環到的元素比個人最小值還要小,就把當前的元素賦值給個人最小值,總和就是全部的元素相加,平均值爲總和/數組的長度。詳細的代碼以下:windows
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。