Typem wartościowym w C# są typy proste, wyliczeniowe, oraz struktury. Niejawnie rozszerzają one klasę System.ValueType, która warunkuje m.in. umieszczenie ich na stosie.
Typy referencyjne natomiast to np.: klasy, tablice, interfejsy i delegaty. I to właśnie w tej grupie znajduje się string. Wydaje mi się, że łatwiej będzie Ci to zauważyć na przykładzie z klasą:
using System;
namespace stringProject
{
class MainClass
{
public static void Main(string[] args)
{
Foo someOtherFoo = new Foo("B");
Foo foo = someOtherFoo;
someOtherFoo = new Foo("C");
}
}
class Foo
{
public string SomeProperty { get; private set; }
public Foo(string bar) { SomeProperty = bar; }
}
}
W przykładzie, zmiennej someOtherFoo przypisujesz referencję do nowopowstałego obiektu Foo("B"), a zmiennej foo, przypisujesz referencję zmiennej someOtherFoo. Teraz obie zmienne wskazują na ten sam obiekt. Następnie zmiennej someOtherFoo przypisujesz referencję do zupełnie nowego obiektu Foo("C"), foo natomiast, cały czas posiada referencję do starego obiektu Foo("B"). To samo jednak dzieje się w sytuacji gdy po prostu przypisujesz wartości dwóm stringom:
using System;
namespace anotherstringproject
{
class MainClass
{
public static void Main (string[] args)
{
string me = "Jurek";
string copy = me;
me = "Marek";
}
}
}
Nie kopiujesz tutaj jednego stringa do drugiego. Zmienna -me- otrzymuje referencję do "Jurek", zmienna -copy- otrzymuje tę samą referencję, czyli obie zmienne wskazują to samo miejsce. Następnie -me- podajesz nową referencję na "Marek", ale -copy- cały czas pokazuje starą wartość (poprzedni adres). Teraz rozumiesz? W stringu nie jest to tak widoczne, bo posługujemy się zwykłym operatorem "=", który w przypadku tej klasy w pewien sposób symuluje zachowanie typu wartościowego.