一、原來函數這樣傳參
先看一個函數和函數調用。
static void Main(string[] args) { int num = 10; Test(num);//局部變量在使用之前賦值 //Test(10); //直接為局部變量賦值 } static void Test(int i)//i 相當於一個局部變量 { i++; }
Test函數定義了一個int 類型的變量i作為參數,這個地方相當於聲明了一個局部變量,而局部變量使用之前必須賦值,這就是為什么函數使用的時候要賦值(傳一個值進去)。
假如不想給參數賦值怎么辦?那就在函數聲明參數的時候給參數(局部變量)賦值,這樣調用函數的時候就可以不給參數傳值。如下:
static void Main(string[] args) { int x= Test();//可以不傳值 int y= Test(20);//也可以傳值 Console.WriteLine(x); Console.WriteLine(y); Console.Read(); } static int Test(int i=10)//為局部變量賦值,傳參數的時候可以不為i賦值 { i++; return i; }
注意:賦初值的參數必須放在參數列表最右側,可以有多個帶初值的參數。
作用:為參數賦了初值,在調用的時候可以賦值也可以不賦值,作用是為參數指定默認值,。
static void Test(int a,int b=20, int i=10) { //to do }
在為方法傳參數的時候必須按照參數聲明的順序傳,這個一直是這樣做的,也沒多想過,其實也可以不按照傳參的順序,如下:
static void Main(string[] args) { Test2(s:"hello",b:true ,i:10); //請看這個地方 Console.Read(); } static void Test2(int i,string s,bool b) { Console.WriteLine(i); Console.WriteLine(s); Console.WriteLine(b); }
傳參的時候指定哪個參數傳什么值就可以不按照順序傳參,這個不是很常用,但是以前不知道,又長見識了。
補充:評論你有人問,如果有重載怎么辦,這個問題,問得非常好。先看一下下面的代碼
static void Main(string[] args) { int x = Test(10); int y = Test(20,30); int z = Test(10, 20, 30); Console.WriteLine(x);//輸出10 Console.WriteLine(y);//輸出50 Console.WriteLine(z);//輸出60 Console.Read(); } static int Test(int i ) { return i; } static int Test(int a,int b=20) { return a + b; } static int Test(int a,int b=20,int c=30) { return a + b + c; }
當有重載的時候,不給帶有默認值參數賦值,他會優先執行,不帶默認參數的函數。
二、params 參數數組(可變參數)
我們知道數組的長度是不可變的。當我們把一個數組作為參數傳遞的時候,想改變數組長度不是一件容易的事兒。params 參數數組就可以隨便指定參數長度,也不用在傳參的時候去特意定義一個數組傳參。使用非常方便。
例:
static void Main(string[] args) { int[] arr = new int[]{1,2,4,5,6}; Test1(arr); Console.WriteLine(); Test2(1,2,4,56,78,8,4); Console.WriteLine(); Test2(1,5,7); Console.Read(); } static void Test1(int [] arr ) { for (int i = 0; i < arr .Length ; i++) { Console.Write(arr [i]+" "); } } static void Test2(params int[] arr) //params 數組 { for (int i = 0; i < arr.Length; i++) { Console.Write(arr [i]+" "); } }
params 參數數組,作為參數的時候,參數個數是可變的,當然也可以為0,但是用params 參數數組的時候,一個函數里只有一個params參數,並且必須放在參數列表的最后。
params用法: 1、用來修飾方法的參數,而且只能修飾一維數組;
2、一個方法只能出現一個params參數,並且必須把params參數數組放在最后,不能帶有默認值;
3、調用方法的時候,params修飾的參數,可以傳一個數組,也可以傳數組的元素,也可以什么都不傳(長度就為0);
在控制台應用程序中,如Console.WriteLine("我叫{0},今年{1}歲,喜歡{2}","Vivu","22","C#");其實就用到了params參數,這個重載就是:
console.WriteLine(string.Format,Params string[] arr);
總結:params 參數修飾的數組相當於長度可變的參數數組。它是修飾參數(一維數組)的一個關鍵字。用處就是在不知道參數個數或參數個數有可能發生變化的情況下使用。
三、ref和out參數修飾符
ref:
值類型在傳遞值的時候,只是復制了一份值賦給另一個變量,另一個變量改變並不能改變原有的值。例如:
int num = 200; int a = num; a -= 100; Console.WriteLine(num);//輸出200 Console.WriteLine(a);//輸出100
但是,假如num代表我錢包里的錢,我把錢包交給別人(int a=num),別人用了100(a-=100),這時候,我錢包里的錢(num)應該是多少?按照上面的方式執行就會出錯,錢包里的錢是不會變的,因為在傳值的時候只是復制了num的一份值給a,a改變並不會改變num的值。那該怎么辦???
如果我傳遞的值是num的引用(可以理解為地址),那么a 改變了num就也會改變了。但是int 類型是值傳遞,怎么辦,把它變為引用就要用到ref和out參數。
ref和out參數的作用就是把值傳遞改為引用傳遞。
改寫上面的錢包的例子。
static void Main(string[] args) { int num = 200; int res =Test(ref num ); Console.WriteLine(num );//輸出100 Console.WriteLine(res );//輸出100 Console.Read(); } static int Test(ref int a) { a -= 100; return a; }
在內存圖中分析一下ref參數:
ref參數可以按引用類型傳遞,如果ref修飾的是引用類型的參數呢?先看下面的例子:
先創建一個person類

private int _age; private string _name; public string Name { get { return _name; } set { _name = value; } } public int Age { get { return _age; } set { _age = value; } }
再看一下面ref修飾引用類型的情況。
static void Main(string[] args) { Person p = new Person() { Name ="紅紅"}; Test1(p); Console.WriteLine(p.Name); //輸出什么??? TestRef1(ref p); Console.WriteLine(p.Name); //輸出什么??? Test2(p); Console.WriteLine(p.Name); //輸出什么??? TestRef2(ref p); Console.WriteLine(p.Name); //輸出什么??? Console.Read(); } static void Test1(Person p) { p = new Person() { Name = "綠綠" }; } static void TestRef1(ref Person p) { p = new Person() { Name ="藍藍"}; } static void Test2(Person p) { p.Name = "嘿嘿"; } static void TestRef2(ref Person p) { p.Name = "掰掰"; }
輸出結果是,紅紅,藍藍,嘿嘿,掰掰。畫一下內存圖很好分析。引用類型本來傳遞的就是地址,所以引用類型使用ref參數和不使用是一樣的。這里偷一下懶,想知道的去運行,畫一下內存圖吧!!!
ref用法:1、使用ref必須在參數聲明和調用的時候都帶上ref關鍵字;
2、只能修飾變量,不能修飾常量;
3、ref在方法中可以對ref修飾的值不改變,但是在傳參前必須給參數賦值;
out:
ref 在使用之前必須賦初始值,它主要側重於改變,修改值。使用ref,在函數聲明與調用的時候必須在參數前面加上ref。out參數的作用與使用方法與ref類似,與ref不同的是out在使用前不必賦初始值,但在返回的時候必須為他賦值,所以out主要側重於輸出。out修飾符參數例子:
static void Main(string[] args) { int num = 200; int b; int a = TestOut(200,out b); Console.WriteLine(a);//輸出100 Console.WriteLine(b);//輸出200 Console.Read(); } static int TestOut(int a,out int b) { b = a; a -= 100; return a; }
總結:ref和out參數修飾符,都是把參數按引用類型傳遞,但是ref側重於改變值,而out側重於輸出。一個函數只有一個輸出值,但想返回多個值的時候就用out參數修飾符。
ref在使用之前必須賦值,out在返回之前必須賦值。ref和out在函數使用和調用的時候,參數前面必須加ref和out參數。