Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
My_shpory_Ivan_Ivanich (2).docx
Скачиваний:
0
Добавлен:
01.07.2025
Размер:
149.35 Кб
Скачать

4. Строки и строковый пул

Пул строк (англ. string pooling) относится к двум видам оптимизации компилятора, связанным со строками:

  1. Снижение объёма кода путём объединения одинаковых строк из разных модулей.

  2. Ленивые присваивания строк с использованием счётчика ссылок (copy-on-write).

При обработке исходного кода компилятор должен каждую литеральную строку поместить в метаданные управляемого модуля. Если одна строка встречается в исходном коде много раз, размещение всех таких строк в метаданных приведет к росту результирующего файла.

Чтобы не допустить роста объёма кода, многие компиляторы (в том числе компилятор C#) хранят литеральную строку в метаданных модуля только в одном экземпляре. Все упоминания этой строки в исходном коде компилятор заменяет ссылками на её экземпляр в метаданных. Благодаря этому заметно уменьшается размер модуля. Способ не нов — в компиляторах C/C++ этот механизм существует уже давно. В компиляторе Microsoft C/C++ это называется созданием пула строк (string pooling). Это ещё одно средство, позволяющее ускорить обработку строк.

Строковые литералы помещаются в пул в момент компиляции, а новые, динамические строки взаимодействуют с этим пулом в момент выполнения. Получается, что каждая новая строка сравнивается со всеми уже существующими, что может влиять на производительность кода.

Строка в .NET является последовательностью символов. Каждый символ является символом Юникода в диапазоне от U+0000 до U+FFFF (будет рассмотрено далее). Строковый тип имеет следующие характеристики:

  1. Строка является ссылочным типом

  2. Строка является неизменяемой (Никак невозможно изменить содержимое созданной строки, по крайней мере в безопасном (safe) коде и без рефлексии).

  3. Строка может содержать значение null

  4. Строка переопределяет оператор равенства ==

  5. Интернирование (В .NET существует понятие «пула интернирования» (intern pool). По своей сути это всего лишь набор строк, но он обеспечивает то, что когда вы в разных местах программы используете разные строки с одним и тем же содержимым, то это содержимое будет храниться лишь один раз, а не создаваться каждый раз по-новому.)

  6. Литерал — это, грубо говоря, «захардкодженное» в коде значение строки. Есть два типа строковых литералов в C# — стандартные (”x”) и дословные (@”x”).

5. Обобщенные типы, ограничения в параметрах обобщенных типов, типы допускающие null значение

// ЭТО Generics

Универсальные шаблоны были добавлены в язык C# версии 2.0 и среду CLR. Универсальные шаблоны в платформе .NET Framework представляют концепцию параметров типов, которые позволяют разрабатывать классы и методы, не придерживающиеся спецификации одного или нескольких типов до тех пор, пока класс или метод не будет объявлен клиентским кодом и пока не будет создан его экземпляр. Например, используя параметр универсального типа T можно написать отдельный класс, который другой клиентский код сможет использовать без риска привидения во время выполнения или операций упаковки-преобразования, как показано в следующем примере:

Общие сведения об универсальных шаблонах

  • Используйте универсальные типы для достижения максимального уровня повторного использования кода, безопасности типа и производительности.

  • Наиболее частым случаем использования универсальных шаблонов является создание классов коллекции.

  • Библиотека классов платформы .NET Framework содержит несколько новых универсальных классов коллекций в пространстве имен System.Collections.Generic. Их следует использовать по мере возможности вместо таких классов какArrayList в пространстве имен System.Collections.

  • Можно создавать собственные универсальные интерфейсы, классы, методы, события и делегаты.

  • Доступ универсальных классов к методам можно ограничить определенными типами данных.

  • Сведения о типах, используемых в универсальном типе данных, можно получить во время выполнения путем рефлексии.

Ограничения параметров типа

Ограничение

Описание

where T: struct

Аргумент типа должен иметь тип значения. Допускается указание любого типа значения, кроме Nullable. Дополнительные сведения см. в разделе Использование допускающих значение NULL типов (Руководство по программированию на C#).

where T : class

Аргумент типа должен иметь ссылочный тип; это также распространяется на тип любого класса, интерфейса, делегата или массива.

where T : new()

Аргумент типа должен иметь открытый конструктор без параметров. При использовании с другими ограничениями ограничение new() должно устанавливаться последним.

where T : <base class name>

Аргумент типа должен являться или быть производным от указанного базового класса.

where T : <interface name>

Аргумент типа должен являться или реализовывать указанный интерфейс. Можно установить несколько ограничений интерфейса. Ограничивающий интерфейс также может быть универсальным.

where T : U

Аргумент типа, предоставляемый в качестве T, должен совпадать с аргументом, предоставляемым в качестве U, или быть производным от него.

Ковариантность

List<Manager> ms = GetManagers();

List<Employee> es = ms;

public interface IEnumerable<out T> { /* ... */ }

Обратите внимание на ключевое слово out, модифицирующее определение параметра-типа T. Компилятор, встречая такой модификатор, будет помечать T как ковариантный и проверять, чтобы в определении этого интерфейса все случаи использования T были корректны (другими словами, чтобы такие параметры использовались только как выходные, — вот почему было выбрано ключевое слово out).

Почему же это назвали ковариантностью? Конкретнее, возьмем типы Manager и Employee. Поскольку между этими классами существует связь наследования, допускается неявное ссылочное преобразование (implicit reference conversion) из Manager в Employee:

И теперь из-за аннотации T в IEnumerable<out T> существует еще и неявное ссылочное преобразование из IEnumerable<Manager> в IEnumerable<Employee>. Вот для чего предоставляется аннотация:

Контравариантность

Под контравариантностью подразумевают обратное. Вероятно, вы уже догадались, что это возможно, когда параметр-тип T используется только как входной, и вы совершенно правы. Например, в пространстве имен System содержится интерфейс IComparable<T> с единственным методом CompareTo:

public interface IComparable<in T> {

bool CompareTo(T other);

}

Если у вас есть IComparable<Employee>, вы должны иметь возможность обрабатывать его так, будто это IComparable<Manager>, поскольку единственное, что вы можете сделать, — передать Employee в интерфейс. А раз менеджер является и сотрудником, такая передача должна работать, и она работает. В этом случае параметр-тип T модифицируется ключевым словом in, и в следующем примере функционирует корректно:

IComparable<Employee> ec = GetEmployeeComparer();

IComparable<Manager> mc = ec;

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]