所謂函數或方法,只是一段代碼的進入點,可以理解為主程式的一次中斷調用,調用後恢複現場,也就是說,是在堆棧中分配的一塊地區來處理中斷事件.如果你指望去傳遞一個在堆內分配的一整段資料,簡直是在發瘋,所以傳遞的參數都是引用(實值型別也是指標操作的,什麼都有地址的)
C#中方法的參數有四種類型:
1.值參數:不含任何修飾符。方法中的形參是實參的一份拷貝(副本),形參的改變不會影響到記憶體中實參的的值,實參是安全的。
2.引用參數:以ref修飾符聲明。傳遞的參數實際上是實參的指標,所以在方法中的操作都是直接對實參進行的,而不是複製一個值;可以利用這個方式在方法調用時雙向傳遞參數;為了以ref方式使用參數,必須在方法聲明和方法調用中都明確地指定ref關鍵字,並且實參變數在傳遞給方法前必須進行初始化。
3.輸出參數:以out修飾符聲明。和ref類似,它也是直接對實參進行操作。在方法聲明和方法調用時都必須明確地指定out關鍵字。out參數聲明方式不要求變數傳遞給方法前進行初始化,因為它的含義只是用作輸出目的。但是,在方法返回前,必須對out參數進行賦值。
4.數組型參數:以params修飾符聲明。params關鍵字用來聲明可變長度的參數列表。方法聲明中只能包含一個params參數。
按引用傳遞實值型別是有用的,但是 ref 對於傳遞參考型別也是很有用的。這允許被調用的
方法修改該引用所引用的對象,因為引用本身是按引用來傳遞的。
自己解釋一下,(實值型別和參考型別的地址放在堆棧中,引用的對象放在堆中)
c#中都是傳的都是堆棧的內容(int型直接就在棧裡面了)
1.如果是實值型別的傳值(預設),那麼不管是實值型別或者是參考型別,那麼傳的堆棧內容是它本生的一個副本.
2.如果是參考型別傳值(ref,out),傳遞的參數實際上是參數的實際指標,所以在方法中的操作都是直接對他進行的
在這裡為大家解一下疑惑
類
public class _class
{
public string w = "A";
}
方法1
public void ww(_class j)
{
_class jj = new _class();
jj.w = jj.w + "2";
j = jj;
}
方法2
public void ww(ref _class j)
{
_class jj = new _class();
jj.w = jj.w + "2";
j = jj;
}
方法3
public void ww(_class j)
{
j.w = j.w + "2";
}
1.調用方法1時發現參數j執行完方法沒有變化,說明沒有影響參數的值
2.調用方法2時發現參數j執行完方法變為了jj,說明變化可以更改
3.實際這個最有意思,你會發現這時候參數j發生了變化,改這個對象的屬性竟然可以改變值,比較方法1和3會得出結論
雖然值傳遞參考型別時是傳遞一個副本,但是這時候在方法內部調用這個引用中的對象時,竟然是真真實位址的傳遞,可以修改,所以,值傳遞應該只保護傳遞類型的本身,卻沒有為類型內部的類型棄置站台,所以可以直接修改
所以在網上看到有人說數組值傳遞時也可以在方法內部修改,那是因為直接修改數組內部的值了,如果你建立一個數組,再直接賦值給這個參數數組,修改肯定是無效的
本人還是建議盡量不用ref還有盡量用傳回值處理方法,代碼可讀性和可控性都比ref強