Чтение онлайн

ЖАНРЫ

Язык программирования C#9 и платформа .NET5
Шрифт:

.locals init (string V_0)

IL_0000: nop

IL_0001: ldstr "My other string"

IL_0006: stloc.0

IL_0007: ldstr "New string value" /* 70000B3B */

IL_000c: stloc.0

IL_000d: ldloc.0

IL_0013: nop

IL_0014: ret

} // end of method Program::StringsAreImmutable2

Хотя низкоуровневые детали языка CIL пока подробно не рассматривались, обратите внимание на многочисленные

вызовы кода операции
ldstr
("load string" — "загрузить строку"). Попросту говоря, код операции
ldstr
языка CIL загружает новый объект
string
в управляемую кучу. Предыдущий объект
string
, который содержал значение
"Му other string"
, будет со временем удален сборщиком мусора.

Так что же в точности из всего этого следует? Выражаясь кратко, класс

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

Однако когда строится приложение, в котором текстовые данные будут часто изменяться (подобное текстовому процессору), то представление обрабатываемых текстовых данных с применением объектов

string
будет неудачным решением, т.к. оно практически наверняка (и часто косвенно) приведет к созданию излишних копий строковых данных. Тогда каким образом должен поступить программист? Ответ на этот вопрос вы найдете ниже.

Использование типа System.Text.StringBuilder

С учетом того, что тип

string
может оказаться неэффективным при необдуманном использовании, библиотеки базовых классов .NET Core предоставляют пространство имен
System.Text
. Внутри этого (относительно небольшого) пространства имен находится класс
StringBuilder
. Как и
System.String
, класс
StringBuilder
определяет методы, которые позволяют, например, заменять или форматировать сегменты. Для применения класса
StringBuilder
в файлах кода C# первым делом понадобится импортировать следующее пространство имен в файл кода (что в случае нового проекта Visual Studio уже должно быть сделано):

// Здесь определен класс StringBuilder:

using System.Text;

Уникальность класса

StringBuilder
в том, что при вызове его членов производится прямое изменение внутренних символьных данных объекта (делая его более эффективным) без получения копии данных в модифицированном формате. При создании экземпляра
StringBuilder
начальные значения объекта могут быть заданы через один из множества конструкторов. Если вы не знакомы с понятием конструктора, тогда пока достаточно знать только то, что конструкторы позволяют создавать объект с начальным состоянием при использовании ключевого слова
new
. Взгляните на следующий пример применения
StringBuilder
:

static void FunWithStringBuilder

{

Console.WriteLine("=> Using the StringBuilder:");

StringBuilder sb = new StringBuilder("**** Fantastic Games ****");

sb.Append("\n");

sb.AppendLine("Half Life");

sb.AppendLine("Morrowind");

sb.AppendLine("Deus Ex" + "2");

sb.AppendLine("System Shock");

Console.WriteLine(sb.ToString);

sb.Replace("2", " Invisible War");

Console.WriteLine(sb.ToString);

Console.WriteLine("sb has {0} chars.", sb.Length);

Console.WriteLine;

}

Здесь

создается объект
StringBuilder
с начальным значением
"**** Fantastic Games ****"
. Как видите, можно добавлять строки в конец внутреннего буфера, а также заменять или удалять любые символы. По умолчанию
StringBuilder
способен хранить строку только длиной 16 символов или меньше (но при необходимости будет автоматически расширяться): однако стандартное начальное значение длины можно изменить посредством дополнительного аргумента конструктора:

// Создать экземпляр StringBuilder с исходным размером в 256 символов.

StringBuilder sb = new StringBuilder("**** Fantastic Games ****", 256);

При добавлении большего количества символов, чем в указанном лимите, объект

StringBuilder
скопирует свои данные в новый экземпляр и увеличит размер буфера на заданный лимит.

Сужающие и расширяющие преобразования типов данных

Теперь, когда вы понимаете, как работать с внутренними типами данных С#, давайте рассмотрим связанную тему преобразования типов данных. Создайте новый проект консольного приложения по имени

TypeConversions
и добавьте его в свое решение. Приведите код к следующему виду:

using System;

Console.WriteLine("***** Fun with type conversions *****");

// Сложить две переменные типа short и вывести результат.

short numb1 = 9, numb2 = 10;

Console.WriteLine("{0} + {1} = {2}",

numb1, numb2, Add(numb1, numb2));

Console.ReadLine;

static int Add(int x, int y)

{

return x + y;

}

Легко заметить, что метод

Add
ожидает передачи двух параметров
int
. Тем не менее, в вызывающем коде ему на самом деле передаются две переменные типа
short
. Хотя это может выглядеть похожим на несоответствие типов данных, программа компилируется и выполняется без ошибок, возвращая ожидаемый результат 19.

Причина, по которой компилятор считает такой код синтаксически корректным, связана с тем, что потеря данных в нем невозможна. Из-за того, что максимальное значение для типа

short
(32 767) гораздо меньше максимального значения для типа
int
(2 147 483 647), компилятор неявно расширяет каждое значение
short
до типа
int
. Формально термин расширение используется для определения неявного восходящего приведения которое не вызывает потерю данных.

Поделиться с друзьями: