Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
C# Лекция_7 Символы и строки.docx
Скачиваний:
39
Добавлен:
18.12.2018
Размер:
957.03 Кб
Скачать
    1. Строковые константы

Без констант не обойтись. В C# существуют два вида строковых констант:

  • обычные константы, которые представляют строку символов, заключенную в кавычки;

  • @-константы, заданные обычной константой c предшествующим знаком @.

В обычных константах некоторые символы интерпретируются особым образом. Связано это, прежде всего, с тем, что необходимо уметь задавать в строке непечатаемые символы, такие как, например, символ табуляции. Возникает необходимость задавать символы в виде escape-последовательностей. Для всех этих целей используется комбинация символов, начинающаяся символом "\" - обратная косая черта. Так, пары символов: "\n", "\t", "\\", "\"" задают соответственно символ перехода на новую строку, символ табуляции, сам символ обратной косой черты, символ кавычки, вставляемый в строку, но не сигнализирующий о ее окончании. Комбинация "\xNNNN" задает символ, определяемый шестнадцатеричным кодом NNNN. Хотя такое решение возникающих проблем совершенно естественно, иногда возникают неудобства: например, при задании констант, определяющих путь к файлу, приходится каждый раз удваивать символ обратной косой черты. Это одна из причин, по которой появились @-константы.

В @-константах все символы трактуются в полном соответствии с их изображением. Поэтому путь к файлу лучше задавать @-константой. Единственная проблема в таких случаях: как задать символ кавычки, чтобы он не воспринимался как конец самой константы. Решением является удвоение символа. Вот соответствующие примеры:

/// <summary>

/// Два вида констант

/// </summary>

public void TestConstants()

{

string s1 = "\x50";

string s2 = @"\x50""";

bool b1 = (s1 == s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}",

s1, s2, b1);

s1 = "c:\\c#book\\ch5\\chapter5.doc";

s2 = @"c:\c#book\ch5\chapter5.doc";

b1 = (s1 == s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}",

s1, s2, b1);

s1 = "\"A\"";

s2 = @"""A""";

b1 = (s1 == s2);

Console.WriteLine("s1={0}, s2={1}, b1={2}",

s1, s2, b1);

}

Первая проверка эквивалентности строк в этом примере даст значение False, остальные - True.

    1. Неизменяемый класс string

В языке C# существует понятие неизменяемый (immutable) класс. Для такого класса невозможно изменить значение объекта. Методы могут создавать новый объект на основе существующего, но не могут изменить значение существующего объекта.

К таким неизменяемым классам относится и класс string. Ни один из методов этого класса не меняет значения существующих объектов. Когда метод изменяет строку, результатом является новая строка - новый объект в куче. Невозможность изменять значения строк касается не только методов. Аналогично при работе со строкой как с массивом разрешено только чтение отдельных символов, но не их замена. Оператор присваивания, в котором делается попытка изменить первый символ строки, не допустим, а потому закомментирован:

//Неизменяемые значения

s1= "Zenon"; ch1 = s1[0];

//s1[0]='L';

По какой причине на класс string наложены такие строгие ограничения? Цель благая. Хотя класс string по целому ряду причин целесообразно отнести к ссылочным типам, но для переменных этого типа хотелось бы иметь ту же семантику, что и для переменных арифметического типа, полагая, что каждая переменная имеет собственную память. Неизменяемость типа обеспечивает эту семантику. Поясним ситуацию на примере.

/// <summary>

/// String - неизменяемый тип данных!

/// </summary>

public void TestUnchanged()

{

string s1 = "Zenon";

string s2 = s1;

Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);

Обе переменные указывают на один объект, у них общая память, одно и то же значение. Представим себе, что s1 хочет изменить свое значение, вызвав метод Insert для вставки нового текста. Но метод Insert класса string реализован как функция, возвращающая строку в качестве результата. Поэтому возможно лишь такое присваивание

s1 = s1.Insert(s1.Length, " - это философ!");

Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);

Теперь в куче два объекта, s1 стала ссылкой на вновь созданный объект, изменение ее значения никак не отразилось на переменной s2. Переменная s2 также может изменить свое значение, например, так:

s2 = s2.Replace(s2[0], 'L') + " - это музыкант!";

Console.WriteLine( "s1 = " + s1 + "\t s2 = " + s2);

}

Строка "Zenon" осталась в куче висячей, без ссылок на нее и является объектом для сборщика мусора. Как видите, невозможность изменять значение строки непосредственно в памяти, где хранится ее значение, гарантирует, что изменение значения строковой переменной никак не отражается на других строковых переменных - это соответствует семантике поведения развернутых типов.

На рис. 7.3 показаны результаты работы метода TestUnchanged.

Рис. 7.3. Тип string - это неизменяемый тип