string是引用类型,但是为什么它在赋值更新时作为值类型工作

Muh*_*han 6 c# string

这是一个简单的代码片段,这让我有点困惑:

string s1 = "abc";
string s2 = s1;
s2 = "123";
Debug.Log(s1 + ":" + s2);
Run Code Online (Sandbox Code Playgroud)

调试结果为abc:123

那么为什么s1没有更新为123,因为s1和s2包含相同的引用,如果一个变量更新它,则第二个将自动更新.

Eve*_*rts 6

这是对参考文献使用的常见误解.

s1是引用类型,但其内容是值.您可以认为所有变量都是值类型,但编译器处理它们的方式因值或引用类型而异.

    string s1 = "abc"; 
Run Code Online (Sandbox Code Playgroud)

s1等于存储"abc"的地址,假设为0x0000AAAA

    string s2 = s1; 
Run Code Online (Sandbox Code Playgroud)

s2指向与s1相同的地址,因此其值与s1相同.两者都具有值0x000AAAA

    s2 = "123"; 
Run Code Online (Sandbox Code Playgroud)

字符串是不可变的,意味着你不能修改字符串,无论何时你分配一个新的值或修改,你在内存中的其他地方创建一个新字符串,而前一个字符串准备好GC,如果需要(实际上不是我们的情况).此时,s1仍然具有值0x0000AAAA,而s2具有新的0X0000BBBB.

    Debug.Log(s1 + ":" + s2);
Run Code Online (Sandbox Code Playgroud)

由于两个点都在不同的内容,它们打印出不同的结果.

它只是一个引用类型,因为变量中包含的值并不是按原样使用,而是用于将指针发送到存储实际对象的内存中的地址位置.

除非你使用out/ref(&在C++中),否则暗示要使用变量的值(地址),最有可能作为参数.

请注意,此行为与任何对象相同,而不仅仅是字符串.

Dog dogA = new Dog();
Dog dogB = dogA;
dogA.name = "Wolfie"; // Affect both since we are dereferencing
dogA = new Dog(); // dogA is new object, dogB is still Wolfie
Run Code Online (Sandbox Code Playgroud)

编辑:OP需要解释ref/out.

当您想要更改对象时,您会想到以下内容:

void ChangeObject(GameObject objParam)
{
   objParam = new GameObject("Eve");
}

void Start(){
    GameObject obj = new GameObject("Adam");
    ChangeObject(obj);
    Debug.Log(obj.name); // Adam...hold on should be Eve (??!!)
}
Run Code Online (Sandbox Code Playgroud)

ChangeObject获取GameObejct作为参数,编译器将obj(00000AAAA)中包含的值复制到objParam上,它复制它并且两者现在具有相同的值.

在该方法中,objParam被赋予一个新值,并且与该方法之外的obj不再相关.objParam是方法的本地,并在完成时被删除(游戏对象仍在场景中,但引用丢失).

如果您希望在方法中更改obj:

void ChangeObject(ref GameObject objParam)
{
   objParam = new GameObject("Eve");
}

void Start(){
    GameObject obj = new GameObject("Adam");
    ChangeObject(ref obj);
    Debug.Log(obj.name); // Yeah it is Eve !!!
}
Run Code Online (Sandbox Code Playgroud)

这一次,它不是传递的obj的值,而是obj的地址.因此obj可能包含0x0000AAAA,但它自己的地址是0x0000AABB,然后objParam的值现在是0x0000AABB,更改objParam意味着更改存储在0x0000AABB的值.

out和ref的工作方式相同,只有那个需要在方法中分配一个值,而ref可以离开方法而不影响给定的参数.