A distinção entre tipos de referência e tipos de valor é basicamente uma troca de desempenho no design do idioma. Os tipos de referência têm alguma sobrecarga na construção e destruição e coleta de lixo, porque são criados no heap. Os tipos de valor, por outro lado, têm sobrecarga nas chamadas de método (se o tamanho dos dados for maior que um ponteiro), porque todo o objeto é copiado e não apenas um ponteiro. Como as strings podem ser (e geralmente são) muito maiores que o tamanho de um ponteiro, elas são projetadas como tipos de referência. Além disso, como Servy apontou, o tamanho de um tipo de valor deve ser conhecido em tempo de compilação, o que nem sempre é o caso para seqüências de caracteres.
A questão da mutabilidade é uma questão separada. Os tipos de referência e os tipos de valor podem ser mutáveis ou imutáveis. Os tipos de valor são tipicamente imutáveis, pois a semântica para tipos de valor mutável pode ser confusa.
Os tipos de referência geralmente são mutáveis, mas podem ser projetados como imutáveis, se fizer sentido. As strings são definidas como imutáveis porque possibilitam certas otimizações. Por exemplo, se a mesma string literal ocorrer várias vezes no mesmo programa (o que é bastante comum), o compilador poderá reutilizar o mesmo objeto.
Então, por que "==" está sobrecarregado para comparar seqüências de caracteres por texto? Porque é a semântica mais útil. Se duas seqüências de caracteres forem iguais ao texto, elas podem ou não ser a mesma referência de objeto devido às otimizações. Portanto, comparar referências é bastante inútil, enquanto comparar texto é quase sempre o que você deseja.
Falando de maneira mais geral, Strings tem o que é chamado de semântica de valores . Esse é um conceito mais geral que os tipos de valor, que é um detalhe de implementação específico do C #. Os tipos de valor têm semântica de valor, mas os tipos de referência também podem ter semântica de valor. Quando um tipo tem semântica de valor, você não pode realmente dizer se a implementação subjacente é um tipo de referência ou tipo de valor; portanto, você pode considerar isso um detalhe da implementação.
is
testes de lado), a resposta é provavelmente "por razões históricas". O desempenho da cópia não pode ser o motivo, pois não há necessidade de copiar fisicamente objetos imutáveis. Agora é impossível mudar sem quebrar o código que realmente usais
verificações (ou restrições semelhantes).