Класс System:: String (Система::Строка) инкапсулирует как управляемый объект строку символов Unicode. Класс String (Строка) определен в пространстве имен System (Системное пространство имен) и является стандартной частью .NET Framework. Тип String (Строка) представляет собой конечный (sealed) класс; это означает, что он не может быть базовым для другого класса. Сам класс String (Строка) — производный от класса System: :Object (Система::Объект), являющегося основой иерархии классов .NET. Объект String (Строка) — неизменяемый, т.е. будучи однажды инициализированным, он не может быть изменен. Класс String (Строка) содержит методы, которые можно использовать для изменения объекта String (Строка), такие, как Insert (Вставка), Replace (Замена) и PadLeft. Однако, в действительности, указанные методы никогда не изменяют исходный объект. Вместо этого они возвращают новый объект String (Строка), содержащий измененный текст. Если вы хотите получить возможность изменять исходные данные, вам следует обратить внимание на класс StringBuilder, а не на сам класс String (Строка). В следующем фрагменте кода показано, что метод Replace (Замена) не влияет на содержимое исходного объекта String (Строка), но изменяет содержимое объекта StringBuilder:
//StringReplace.срр
#using <mscorlib.dll>
using namespace System; // для консоли и строк
// использовать пространство имен Система;
using namespace System::Text; // для StringBuilder
// использовать пространство имен Система::Текст;
void main(void) {
Console::WriteLine("String is immutable:");
// ("Строка является неизменной: ");
String *psl = S"Hello World"; // Строка "Привет, Мир"
String *ps2 = psl->Replace('Н', 'J'); // Замена
Console::WriteLine(psl);
Console::WriteLine(ps2);
Console::WriteLine("StringBuilder can be modified:"); // ("StringBuilder может изменяться: ");
StringBuilder *psbl = new StringBuilder(S"Hello World"); // Привет, Мир
StringBuilder *psb2 = psbl->Replace('H', 'J'); // Замена
Console::WriteLine(psb1);
Console::WriteLine(psb2);
}
Информация, выведенная на экран профаммой, показывает, что действительно, содержимое объекта, на который указывает psl, не изменяется, т.е. метод Replace (Замена) не изменяет исходный объект String (Строка). С другой стороны, объект *psbl изменяется методом Replace (Замена).
String is immutable:
Hello World
Jello World
StringBuilder can be modified:
Jello World
Jello World
Перевод такой [Добавлен редактором русского перевода. — Прим. ред.]:
Строка является неизменной:
Привет, Мир
Jello Мир
StringBuilder может измениться:
Jello Мир
Jello Мир
В приведенном выше фрагменте кода вы можете заметить строковые литералы, определенные с префиксом S и без него. Строковый литерал, определенный с использованием только кавычек, является указателем на char (символ), т.е. указателем на последовательность символов ASCII, заканчивающуюся нулем. Такой указатель не является указателем на объект String (Строка). А строковый литерал, определенный с префиксом S, является указателем на управляемый объект String (Строка). Префикс L, не использовавшийся в предыдущем примере, обозначает строку символов Unicode, которая также не является объектом String (Строка). Следующий фрагмент демонстрирует эти три типа строк:
char *psl = "ASCII string literal"; // неуправляемый
// символ *psl = "строковый литерал ASCII ";
_wchar_t *ps2 = L"Unicode string literal"; // неуправляемый
// L " строковый литерал Уникода ";
String *ps3 = S"String object literal"; // управляемый
// Строка *ps3 = S " строковый литерал - объект String ";
Класс String (Строка) содержит много полезных методов. Так, для сравнения объектов можно использовать метод Equals (Равняется), что продемонстрировано в следующем примере. Подробнее о методах объекта String (Строка) можно узнать из документации по .NET SDK.
//Strings.срр
fusing <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
void main(void) {
String *pstrl = new String ("hello");
// Строка *pstrl = новая Строка ("привет");
String *pstr2 = new String("hello");
// Строка *pstr2 = новая Строка ("привет");
if (pstrl->Equals(pstr2))
// если (pstrl-> Равняется (pstr2))
Console::WriteLine("equal"); // равны - выполняется else
Console::WriteLine("not equal"); // не равный - не
// выполняется if (pstrl==pstr2) // если (pstrl == pstr2)
Console::WriteLine("equal"); // равны - не выполняется else
Console::WriteLine("not equal"); // не равный - выполняется }
Результат работы программы показывает разницу между сравнением объектов String (Строка) с помощью метода Equals (Равняется) и оператора ==. Метод Equals (Равняется) проверяет равенство содержимого объектов, тогда как оператор == проверяет лишь равенство указателей (т.е. равенство адресов объектов в памяти).
Equal
not equal
Вот перевод [Добавлен редактором русского перевода. — Прим. ред.]:
равны
не равны
Метод ToString обеспечивает представление объекта String (Строка) для любого управляемого типа данных. Хотя метод ToString не является автоматически доступным для неуправляемых классов, он доступен для упакованных значимых и упакованных примитивных типов, таких, как int или float (с плавающей точкой). Упаковка и распаковка, также как значимые типы, управляемые и неуправляемые типы, будут рассмотрены ниже в этой главе.
Метод ToString наиболее часто используется для вывода информации, а также при отладке, и создаваемые управляемые классы обычно заменяют ToString так, чтобы он возвращал определенную разработчиком, удобочитаемую информацию об объекте. Метод Obj ect: : ToString просто возвращает полное имя класса данного объекта и его реализация (не особо полезная, впрочем) доступна через наследование любому управляемому типу. Следующий пример демонстрирует некоторые аспекты работы метода ToString:
//ToString.cpp
#using <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
_gc class ClassWithToString
// класс сборщика мусора ClassWithToString
{
public:
String *ToString() // отмена {
return new String("SomeClass - override"); // возвратить новую Строку ("SomeClass - отмена");
Результат работы программы приведен ниже. Заметьте, что метод ToString можно вызывать явно как аргумент перегруженного метода WriteLine объекта String (Строка), а можно вызвать перегруженный метод WriteLine объекта String (Строка), который сам вызовет метод ToString. Заметьте также, что даже управляемый массив (который, на самом деле, является управляемым типом) поддерживает метод ToString.
3
3
SomeClass - override SomeClass - override ClassNoToString
ClassNoToString System.Int32[] System.Int32[]
Все идентичные строковые литералы типа String (Строка) автоматически представляются указателями на объекты, являющиеся экземплярами одного класса String (Строка). Это справедливо для объектов, представленных строковыми литералами типа string (Строка), — такие объекты задаются с помощью взятой в кавычки строки. Однако это не справедливо для строковых объектов String (Строка), явно создаваемых с помощью оператора new (создать). Следующий пример подтверждает это. В нем сравниваются два указателя на объект String (Строка), созданных с помощью оператора new (создать). Выведенные на консоль результаты подтверждают, что два идентичных строковых объекта string (Строка), определенных как взятые в кавычки одинаковые последовательности символов, являются одним и тем же объектом (выражение pstrl==pstr2 истинно для строковых объектов String (Строка)). С другой стороны, два одинаковых строковых объекта string (Строка), созданных с помощью оператора new (создать), являются на самом деле разными объектами (выражение pstrl==pstr2 имеет значение false (ложь)).
//StringLiteral.срр
#using <mscorlib.dll>
using namespace System;
// использовать пространство имен Система;
void main(void) {
String *pstrl; // Строка
String *pstr2; // Строка
// сравнение объектов - строковых литералов типа String
pstrl = S"hello"; // привет
pstr2 = S"hello"; // привет
if (pstrl->Equals(pstr2)) // если (pstrl-> Равняется (pstr2))
Console::WriteLine("equal"); // равны - выполнен else
Console::WriteLine("not equal"); // не равны - не выполнен if (pstrl==pstr2) // если (pstrl == pstr2)
Console::WriteLine("equal"); // равны - выполнен else
Console::WriteLine("not equal"); // не равны - не выполнен // сравнение новых объектов String (не литералов) pstrl = new String("hello"); // pstrl = новая Строка ("привет"); pstr2 = new String("hello"); // pstr2 = новая Строка ("привет"); if (pstrl->Equals(pstr2) ) // если (pstrl-> Равняется (pstr2))
Console::WriteLine("equal"); // равны - выполнен else
Console::WriteLine("not equal"); // не равны - не выполнен if (pstrl==pstr2) // если (pstrl == pstr2)
Console::WriteLine("equal"); // равны - не выполнен else
Console::WriteLine("not equal"); // не равны - выполнен }
Программа напечатает:
equal equal equal not equal
Вот перевод [Добавлен редактором русского перевода. — Прим. ред.]:
равны
равны
равны
не равны
Управляемые строковые литералы String (Строка) и неуправляемые строковые литералы ASCII и Unicode (благодаря автоматической упаковке) можно использовать в выражениях, в которых ожидается использование управляемого строкового объекта String (Строка). Однако управляемый строковый объект String (Строка) нельзя использовать там, где ожидается появление переменных неуправляемых типов. Следующий пример доказывает это. Обратите внимание на закомментированные строки. Не будучи закомментированными, они привели бы к сообщению об ошибке при компиляции.
//MixingStringTypes.срр
fusing <rascorlib.dll>
using namespace System;
// использовать пространство имен Система;
tinclude <wchar.h> // для wchar_t
void ExpectingManagedString(String *str){} // Строка *str void ExpectingASCIIString(char *str){} // символ *str void ExpectingUnicodeString(wchar_t *str){} void main(void) {
// ожидается управляемый тип
ExpectingManagedString(S"hello"); // полное соответствие
// привет ExpectingManagedString("hello"); // нет ошибки
// привет
ExpectingManagedString(L"hello"); // нет ошибки
// привет
// ожидается неуправляемый тип
ExpectingASCIIString("hello"); // полное соответствие
// привет //ExpectingASCIIString(S"hello"); // ошибка!
// привет ExpectingUnicodeString(L"hello"); // полное соответствие
// привет //ExpectingUnicodeString(S"hello"); // ошибка!
// привет }