【又長見識了】函數傳參,params參數,ref和out參數詳解

 

 1、原來函數這樣傳參數組

   先看一個函數和函數調用。 ide

 static void Main(string[] args)
        {
            int num = 10;
            Test(num);//局部變量在使用以前賦值

            //Test(10); //直接爲局部變量賦值
        }
        static void Test(int i)//i 至關於一個局部變量
        {
            i++; 
        }

  Test函數定義了一個int 類型的變量i做爲參數,這個地方至關於聲明瞭一個局部變量,而局部變量使用以前必須賦值,這就是爲何函數使用的時候要賦值(傳一個值進去)。函數

  假如不想給參數賦值怎麼辦?那就在函數聲明參數的時候給參數(局部變量)賦值,這樣調用函數的時候就能夠不給參數傳值。以下:spa

        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;
        }

  注意:賦初值的參數必須放在參數列表最右側,能夠有多個帶初值的參數。code

  做用:爲參數賦了初值,在調用的時候能夠賦值也能夠不賦值,做用是爲參數指定默認值,。orm

       static void  Test(int a,int b=20, int i=10)
        {
           //to do
        }

  

  在爲方法傳參數的時候必須按照參數聲明的順序傳,這個一直是這樣作的,也沒多想過,其實也能夠不按照傳參的順序,以下:blog

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

  傳參的時候指定哪一個參數傳什麼值就能夠不按照順序傳參,這個不是很經常使用,可是之前不知道,又長見識了。內存

 


 

補充:評論你有人問,若是有重載怎麼辦,這個問題,問得很是好。先看一下下面的代碼get

    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;
        }

  當有重載的時候,不給帶有默認值參數賦值,他會優先執行,不帶默認參數的函數。string


 

2、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用法: 一、用來修飾方法的參數,並且只能修飾一維數組;

           二、一個方法只能出現一個params參數,而且必須把params參數數組放在最後,不能帶有默認值;

           三、調用方法的時候,params修飾的參數,能夠傳一個數組,也能夠傳數組的元素,也能夠什麼都不傳(長度就爲0);

  在控制檯應用程序中,如Console.WriteLine("我叫{0},今年{1}歲,喜歡{2}","Vivu","22","C#");其實就用到了params參數,這個重載就是:

  console.WriteLine(string.Format,Params string[] arr);           

  總結:params 參數修飾的數組至關於長度可變的參數數組。它是修飾參數(一維數組)的一個關鍵字。用處就是在不知道參數個數或參數個數有可能發生變化的狀況下使用。

3、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; }
        }
Person類

  再看一下面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用法:一、使用ref必須在參數聲明和調用的時候都帶上ref關鍵字;

       二、只能修飾變量,不能修飾常量;

       三、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參數。

相關文章
相關標籤/搜索