Rozróżnienie między typami referencyjnymi a typami wartości jest w zasadzie kompromisem wydajnościowym w projekcie języka. Typy referencyjne mają pewne koszty związane z budową i zniszczeniem oraz wyrzucaniem elementów bezużytecznych, ponieważ są tworzone na stercie. Z drugiej strony typy wartości mają narzut na wywołania metod (jeśli rozmiar danych jest większy niż wskaźnik), ponieważ cały obiekt jest kopiowany, a nie tylko wskaźnik. Ponieważ łańcuchy mogą być (i zwykle są) znacznie większe niż rozmiar wskaźnika, są one zaprojektowane jako typy referencyjne. Ponadto, jak wskazał Servy, rozmiar typu wartości musi być znany w czasie kompilacji, co nie zawsze ma miejsce w przypadku łańcuchów.
Kwestia zmienności jest osobną kwestią. Zarówno typy referencyjne, jak i typy wartości mogą być zmienne lub niezmienne. Typy wartości są jednak zwykle niezmienne, ponieważ semantyka zmiennych typów może być myląca.
Typy referencyjne są generalnie zmienne, ale można je zaprojektować jako niezmienne, jeśli ma to sens. Ciągi są zdefiniowane jako niezmienne, ponieważ umożliwia pewne optymalizacje. Na przykład, jeśli ten sam literał ciągu występuje wiele razy w tym samym programie (co jest dość powszechne), kompilator może ponownie użyć tego samego obiektu.
Dlaczego więc „==” jest przeciążone, aby porównać ciągi tekstowe? Ponieważ jest to najbardziej przydatna semantyka. Jeśli dwa ciągi tekstowe są równe, mogą, ale nie muszą być tym samym odwołaniem do obiektu ze względu na optymalizacje. Porównywanie referencji jest więc bezużyteczne, a porównywanie tekstu prawie zawsze jest tym, czego chcesz.
Mówiąc bardziej ogólnie, ciągi mają tak zwaną semantykę wartości . Jest to koncepcja bardziej ogólna niż typy wartości, która jest szczegółem implementacji specyficznym dla języka C #. Typy wartości mają semantykę wartości, ale typy referencyjne mogą również mieć semantykę wartości. Gdy typ ma semantykę wartości, nie można tak naprawdę stwierdzić, czy podstawowa implementacja jest typem referencyjnym czy typem wartości, więc można uznać, że szczegół implementacji.
is
testy), odpowiedź jest prawdopodobnie „z przyczyn historycznych”. Wydajność kopiowania nie może być przyczyną, ponieważ nie ma potrzeby fizycznego kopiowania niezmiennych obiektów. Teraz nie można zmienić bez zerwania kodu, który faktycznie używais
czeków (lub podobnych ograniczeń).