Доказать, что строка (если вы имеете в виду System.String, конечно) является ссылочным типом, довольно просто.
Все типы значений должны наследоваться от ValueType (неявно caurs), но System.String наследуется непосредственно от System.Object, поэтому с подходом исключения не может быть ничего, кроме ссылочного типа.
Console.WriteLine("".GetType().BaseType); //prints System.Object
Console.WriteLine(1.GetType().BaseType); //prints System.ValueType
Чтобы проверить неизменность, вы должны найти любой "мутирующий" метод внутри класса System.String. Я не могу найти ни одного! Потому что все «мутирующие» методы фактически возвращают другой экземпляр, и вы можете легко проверить это, вызвав object.ReferenceEquals:
Console.WriteLine(object.ReferenceEquals(s, s + "1")); //False
Console.WriteLine(object.ReferenceEquals(s, s.Insert(0, "12"))); //False
Вы также можете проверить другие методы, и вы увидите, что все они имеют одинаковое поведение: они возвращают новый объект, но не изменяют существующие значения.
Из Класс System.String Документация:
Неизменяемость и StringBuilder
Класс
Объект String называется неизменным
(только для чтения), потому что его значение не может
быть изменены после того, как он был создан.
Методы, которые появляются для изменения строки
объект фактически возвращает новую строку
объект, содержащий модификацию.