首先明确類型:
常用的值類型有:int double char bool decimal struct enum;
常用的引用類型有:string 數組 自定義類 接口 委托;
值類型的對象直接存在于棧上。
引用類型的對象實際存在于堆上,但是“指針”存在于棧上。
例如 myClass A = new myClass();
A應該存在于棧上,其内容是一個位址,指向的是new myClass的堆中位址。A應該就是一個代理人,通過A可以修改找到真實的對 象。
然後是傳遞方式:
對于兩種類型的傳遞,在非out,ref的情況下都是值傳遞【拷貝】,隻不過引用類型傳遞的是一個位址的拷貝,在函數内對該拷貝的修改實際上是對該拷貝指向的實際内容的修改。值類型是傳遞的是具體内容的拷貝。
1,按值傳遞
值類型按值傳遞,引用類型按值傳遞的實質的是傳遞值,參數為值類型時,“值”為執行個體本身,是以傳遞的是執行個體拷貝,不會對原來的執行個體産生影響;參數為引用類型時,“值”為對象引用,是以傳遞的是引用位址拷貝,會改變原來對象的引用指向。
string是引用類型,string按值傳遞的效果與值類型按值傳遞效果一樣,string在這裡比較特殊。
調用方法發生參數傳遞時,方法根據參數類型先在stack建立一個變量,然後将參數的值指派給該變量。是以,值類型與string類型傳遞執行個體不變,引用類型傳遞位址改變。但如果是按引用傳遞,則都是傳遞位址,執行個體的值都會發生改變。
2,按引用傳遞
按引用傳遞之ref和out,不管是值類型還是引用類型,按引用傳遞必須以ref或者out關鍵字來修飾,ref要求傳遞之前的參數必須首先顯示初始化,而out不需要。也就是說,使用ref的參數必須是一個實際的對象,而不能指向null;而使用out的參數可以接受指向null的對象,然後在調用方法内部必須完成對象的實體化。
值類型按引用傳遞時,不會對值類型裝箱。
按引用傳遞,傳遞的不是參數本身的值,而是參數的位址。如果參數為值類型,則傳遞的是該值類型的位址;如果參數為引用類型,則傳遞的是對象引用的位址,引用類型按引用傳遞結果和按值按引用傳遞一樣。
示範代碼:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public struct StructA
{
public int a;
}
public class ChuandiA
{
public ChuandiA(int _a)
{
a = _a;
}
private int a;
public int A { get { return a; } set { a = value; } }
}
public class ChuandiTest : MonoBehaviour
{
// Use this for initialization
void Start()
{
Debug.Log("=====修改類的成員====");
ChuandiA A = new ChuandiA(0); //對象1
Debug.Log(A.A);
Debug.Log("=======================");
ChangeA(A);
Debug.Log(A.A);
Debug.Log("=====Ref修改類的成員====");
ChuandiA B = A; //B拷貝了A的内容,B和A都指向了對象1。
Debug.Log(A.A);
Debug.Log(B.A);
Debug.Log("=======================");
ChangeA(ref A);
Debug.Log(A.A); //B仍然指向對象1,A已經指向了新的對象。
Debug.Log(B.A); //B仍然
Debug.Log("=====修改結構體的成員===");
StructA sA = new StructA();
StructA sA2 = sA;
sA.a = 33;
Debug.Log(sA.a);
ChangeA2(sA);
Debug.Log("=======================");
Debug.Log(sA.a);
Debug.Log("=======使用ref修改結構體的成員========");
sA.a = 44;
Debug.Log(sA.a);
ChangeA2(ref sA);
Debug.Log("=======================");
Debug.Log(sA.a);
}
public void ChangeA(ChuandiA _ChuandiA)
{
//此時的_ChuandiA是傳入參數的拷貝,由于傳入的參數是引用類型,是以_ChuandiA的内容是一個位址,指向傳入參數。
//首先通過位址修改了【傳入對象】的内容;
_ChuandiA.A = 3;
//然後指向了新的位址,并不會影響傳入對象的内容;
_ChuandiA = new ChuandiA(99);
//此時的_ChuandiA 指向新的ChuandiA,對舊的對象[sA]無影響。
}
public void ChangeA(ref ChuandiA _ChuandiA)
{
//_ChuandiA就是傳入參數,原來傳入參數是一個指針,指向真實的引用類型對象。
_ChuandiA.A = 444;
//修改了_ChuandiA的指向,也就是修改了傳入參數的内容【位址】.
_ChuandiA = new ChuandiA(99);
//傳入參數原來指向的對象仍然是444,不受影響。
}
public void ChangeA2(StructA _ChuandiA)
{
//值類型的值傳遞是拷貝。此時的_ChuandiA是對傳入參數的一個拷貝。
_ChuandiA.a = 3;
}
public void ChangeA2(ref StructA _ChuandiA)
{
//值類型的引用傳遞不是拷貝,此時的_ChuandiA就是傳入參數。
_ChuandiA.a = 3;
}
}