C#中ref與out的區別


// 今天遇到一個問題,需要傳遞一個已經初始化的值,到另外一個函數里遞增,然后返回遞增后的值。
// 順便總結一下out與ref的區別
private  void button1_Click( object sender, EventArgs e)
{
     // ref,out都能修改傳進來的參數的值。
     int refInt =  100;
    RefValue( ref refInt);
    MessageBox.Show(refInt.ToString());
     //
     int outInt =  100;
    outValue( out outInt,  100);
    MessageBox.Show(outInt.ToString());
}
// ref
public  void RefValue( ref  int refInt)
{
    refInt +=  100; // ref引用不需要初始化
}
// 一個函數可以有多個ref參數
public  void RefValue( ref  int refInt, ref  int rInt)
{
    refInt +=  100; // ref引用不需要初始化
}
// out
public  void outValue( out  int outInt,  int i)
{
    outInt = i +  100; // out引用必須初始化
}
/* 函數不可以有多個out參數
public void outValue(out int outInt, out oInt,int i)
{
    outInt = i + 100;//out引用必須初始化
}
*/
url: http://greatverve.cnblogs.com/archive/2012/02/27/ref-out.html
修正:
/* 函數可以有多個out參數 */
public  void outValue( out  int outInt,  out  int oInt, int i)
{
    outInt = i +  100; // out引用必須初始化
    oInt =  100; // out的值必須在方法里定義。
}
-----------------------------------------------------------------------------

ref和out的區別在C# 中,既可以通過值也可以通過引用傳遞參數。通過引用傳遞參數允許函數成員更改參數的值,並保持該更改。若要通過引用傳遞參數, 可使用ref或out關鍵字。ref和out這兩個關鍵字都能夠提供相似的功效,其作用也很像C中的指針變量。它們的區別是:

1、使用ref型參數時,傳入的參數必須先被初始化。對out而言,必須在方法中對其完成初始化。

2、使用ref和out時,在方法的參數和執行方法時,都要加Ref或Out關鍵字。以滿足匹配。

3、out適合用在需要retrun多個返回值的地方,而ref則用在需要被調用的方法修改調用者的引用的時候。

注:在C#中,方法的參數傳遞有四種類型:傳值(by value),傳址(by reference),輸出參數(by output),數組參數(by array)。傳值參數無需額外的修飾符,傳址參數需要修飾符ref,輸出參數需要修飾符out,數組參數需要修飾符params。傳值參數在方法調用過程中如果改變了參數的值,那么傳入方法的參數在方法調用完成以后並不因此而改變,而是保留原來傳入時的值。傳址參數恰恰相反,如果方法調用過程改變了參數的值,那么傳入方法的參數在調用完成以后也隨之改變。實際上從名稱上我們可以清楚地看出兩者的含義--傳值參數傳遞的是調用參數的一份拷貝,而傳址參數傳遞的是調用參數的內存地址,該參數在方法內外指向的是同一個存儲位置。

方法參數上的 ref 方法參數關鍵字使方法引用傳遞到方法的同一個變量。當控制傳遞回調用方法時,在方法中對參數所做的任何更改都將反映在該變量中。

若要使用 ref 參數,必須將參數作為 ref 參數顯式傳遞到方法。ref 參數的值被傳遞到 ref 參數。

傳遞到 ref 參數的參數必須最先初始化。將此方法與 out 參數相比,后者的參數在傳遞到 out 參數之前不必顯式初始化。

屬性不是變量,不能作為 ref 參數傳遞。

如果兩種方法的聲明僅在它們對 ref 的使用方面不同,則將出現重載。但是,無法定義僅在 ref 和 out 方面不同的重載。

out

方法參數上的 out 方法參數關鍵字使方法引用傳遞到方法的同一個變量。當控制傳遞回調用方法時,在方法中對參數所做的任何更改都將反映在該變量中。

當希望方法返回多個值時,聲明 out 方法非常有用。使用 out 參數的方法仍然可以返回一個值。一個方法可以有一個以上的 out 參數。

若要使用 out 參數,必須將參數作為 out 參數顯式傳遞到方法。out 參數的值不會傳遞到 out 參數。

不必初始化作為 out 參數傳遞的變量。然而,必須在方法返回之前為 out 參數賦值。

屬性不是變量,不能作為 out 參數傳遞。


網上有很多文章說ref 只傳值,out傳地址等等這種說法,好像不是非常的准確。以下是我做的實例代碼,大家可以去試試:

 public int  RefValue(int i,ref int j)
        {
            int k = j;
            j =222;
            return i+k;
        }

      
        public int OutValue(int i, out int j)
        {
            j = 222;
            return i + j;
        }

        private void cmdRef_Click(object sender, EventArgs e)
        {
            int m = 0;
            MessageBox.Show(RefValue(1, ref m).ToString());
            MessageBox.Show(m.ToString());
        }

        private void cmdOut_Click(object sender, EventArgs e)
        {
            int m;
            MessageBox.Show(OutValue(1, out m).ToString());
            MessageBox.Show(m.ToString());
        }
借網上總結的一句話說,ref是有進有出,而out是只出不進。
--------------------------------------------------------------------

  ref    
    
  通常我們向方法中傳遞的是值.方法獲得的是這些值的一個拷貝,然后使用這些拷貝,當方法運行完畢后,這些拷貝將被丟棄,而原來的值不將受到影響.此外我們還有其他向方法傳遞參數的形式,引用(ref)和輸出(out).
    
  有時,我們需要改變原來變量中的值,這時,我們可以向方法傳遞變量的引用,而不是變量的值.引用是一個變量,他可以訪問原來變量的值,修改引用將修改原來變量的值.變量的值存儲內存中,可以創建一個引用,他指向變量在內存中的位置.當引用被修改時,修改的是內存中的值,因此變量的值可以將被修改.當我們調用一個含有引用參數的方法時,方法中的參數將指向被傳遞給方法的相應變量,因此,我們會明白,為什么當修改參數變量的修改也將導致原來變量的值.
    
  創建參數按引用傳遞的方法,需使用關鍵字ref.例;

using  System;
    
class  gump
    {
public  double  square( ref  double  x)
{
  x
= x * x;
  
return  x;
}
    }

    
class  TestApp
    {
public  static  void  Main()
{
  gump doit
= new  gump();

  
double  a = 3 ;
  
double  b = 0 ;

  Console.WriteLine(\
" Before square->a={0},b={1}\",a,b);

  b
= doit.square( ref  a);
  Console.WriteLine(\
" After square->a={0},b={1}\",a,b);
}
    }

  通過測試,我們發現,a的值已經被修改為9了.

  out
    
  通過指定返回類型,可以從方法返回一個值,有時候(也許還沒遇到,但是我們應該有這么個方法),需要返回多個值,雖然我們可以使用ref來完成,但是C#專門提供了一個屬性類型,關鍵字為out.介紹完后,我們將說明ref和out的區別.
  
通過使用out關鍵字,我們改變了三個變量的值,也就是說out是從方法中傳出值.

using  System;
    
class  gump
    {
public  void  math_routines( double  x, out  double  half, out  double  squared, out  double  cubed)
// 可以是:public void math_routines( // ref double x,out double half,out double squared,out double cubed)
// 但是,不可以這樣:public void math_routines(out double x,out double half,out double squared,out double cubed),對本例來說,因為輸出的值要靠x賦值,所以x不能再為輸出值
{
  half
= x / 2 ;
  squared
= x * x;
  cubed
= x * x * x;
}
    }

    
class  TestApp
    {
public  static  void  Main()
{
    gump doit
= new  gump();

    
double  x1 = 600 ;
    
double  half1 = 0 ;
    
double  squared1 = 0 ;
    
double  cubed1 = 0 ;
    [Page]
    
/*
     double x1=600;
     double half1;
     double squared1;
     double cubed1;
    
*/

    Console.WriteLine(\
" Before method->x1={0}\",x1);
    Console.WriteLine(\ " half1={0}\",half1);    Console.WriteLine(\"squared1={0}\",squared1);
    Console.WriteLine(\ " cubed1={0}\",cubed1);



    doit.math_rountines(x1,
out  half1, out  squared1, out  cubed1);
    
    Console.WriteLine(\
" After method->x1={0}\",x1);
    Console.WriteLine(\ " half1={0}\",half1);
    Console.WriteLine(\ " squared1={0}\",squared1);
    Console.WriteLine(\ " cubed1={0}\",cubed1);
}
    }

  我們發現,ref和out似乎可以實現相同的功能.因為都可以改變傳遞到方法中的變量的值.但是,二者本質本質的區別就是,ref是傳入值,out是傳出值.在含有out關鍵字的方法中,變量必須由方法參數中不含out(可以是ref)的變量賦值或者由全局(即方法可以使用的該方法外部變量)變量賦值,out的宗旨是保證每一個傳出變量都必須被賦值.
    

  上面代碼中被/**/注釋掉的部分,可以直接使用.也就是說,在調用方法前可以不初始化變量.但是\"x1\"是要賦值的,否則要報錯.而ref參數,在傳遞給方法時,就已經是還有值的了,所以ref側重修改.out側重輸出. 
-----------------------------------------------------------------------------

關於c#方法返回多個值的幾個方法

在實際編程中,我們會經常遇到在同一個c#方法中返回多個值的情況,根據本人和經驗,現總結了如下兩種方法:

1.用out 聲明返回值

例public void currentMonthCount(out int monthCome ,out DataTable dtTable)

其中monthCome   dtTable是兩個不同類型的返回值.

此外,還可以既有多個返回值,還可以同時加入傳入參數.

例:public void query(out int come,out   DataTable dtTable, DateTime startDate, DateTime endDate)

其中come    dtTable為返回值,startDate,endDate為傳入參數.

同時注意,前面必須用void修飾,否則會出錯.

調用時:須首先定義返回值的類型,如

調用public void currentMonthCount(out int monthCome ,out DataTable dtTable)這個方法

首先定義:int monthCome;

DataTable dtTable;

cuurentMonthCount(out monthCome,out dtTable);

this.lable1.text=monthCome.toString();

就能得到返回值了.

2,定義object 型函數

例:用一個參數作為條件返回多個不同的值,

public object MakeConnectionMethod(string sql,   executeMethod execMethod)

{

//返回dataSet
             if (strConnection != "" && execMethod == executeMethod.execute_DataSet)
             {

                ..........

                 return mydataset1;
             }


             //添加、刪除、修改
             if (strConnection != "" && execMethod == executeMethod.execute_NoneQuery)
             {
                 ........

                 }
                 return isSucceed;
             }

             //返回關鍵字第一行記錄的arraylist。
             if (strConnection != "" && execMethod == executeMethod.execute_Linekey)
             {
                 .....

                 }
                 return retString;
             }
             return null;
         }

調用時根據不同的參數,可以返回不同的值

 

-------------------------------------------------------------------------------------
一個函數返回多個值 C#
Public  void GetValues( string UserID, string PassWord, out  string  string UserName, out  bool flag)
{
       // 在使用一些判斷為返回值賦值時,最好先在判斷外賦上初始值,否則易報“離開當前方法之前必須對out 參數賦值”錯誤
 
      UserName =  "";
      flag =  true;
 
       if(UserID ==  1 && Password ==  " 123 ")
      {
          UserName =  " 小白 ";
      }
       else
      {
          flag =  false;
      }
}

private  void btnLogin_Click( object sender, System.Web.UI.ImageClickEventArgs e)
{
       // 先對返回的參數進行聲明
       string Name;
       string UserName;
       bool Flag;

      GetValues( " 1 "" 123 ", out Name,  out Flag);
         
       // 此時Name和Flag的值已返回
      
// Name = "小白"
      
// Flag = true

       if(Flag ==  true)
      {
            UserName = Name;
             // UserName被賦值為小白
      }
}

out 關鍵字會導致參數通過引用來傳遞。這與 ref 關鍵字類似,不同之處在於 ref 要求變量必須在傳遞之前進行初始化。若要使用 out 參數,方法定義和調用方法都必須顯式使用 out 關鍵字。盡管作為 out 參數傳遞的變量不需要在傳遞之前進行初始化,但需要調用方法以便在方法返回之前賦值。ref 和 out 關鍵字在運行時的處理方式不同,但在編譯時的處理方式相同。因此,如果一個方法采用 ref 參數,而另一個方法采用 out 參數,則無法重載這兩個方法。 

參考MSDN


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM