.NET framework Колотаев А.В.
На этой лекции: Элементарные типы Значимые и ссылочные типы Упаковка и распаковка значимых типов Равенство и тождество объектов Видимость типов и членов Константы Поля
Элементарные типы Элементарные типы – типы, которые поддерживаются компилятором напрямую и специальным образом обрабатываются: Целочисленные (8,16,32,64 разряда; со знаком и без) С плавающей точкой (float, double, decimal) String Object Char Bool
Элементрные типы
Элементарные типы
Использование псевдонимов vs. имен типов FCL Псевдонимы короче и читабельней В разных языках ключевому слову может соответствовать разные типы FCL: long в C# - это System.Int64, а в С++/CLI – System.Int32 В типах FCL есть методы, в именах которых используются имена типов FCL
Элементарные типы Явное и неявное приведение между элементарными типами Литеральная форма записи
Проверяемые и непроверяемые операции для элементарных типов add/add.ovf; sub/sub.ovf; mul/mul.ovf; conv/conv.ovf По умолчанию проверка отключена. Для ее включения на уровне файла есть ключ /checked+ Операторы checked и unchecked Инструкции checked и unchecked
Ссылочные и значимые типы В CLR тип определяет, каким образом его объекты размещаются в памяти: Объекты ссылочных (reference) типов размещаются только в управляемой куче и удаляются сборщиком мусора. Переменная ссылочного типа хранит указатель на объект, размещенный в куче Объекты значимых (value) типов размещаются на стеке или как поля других типов. Экземплярные поля хранятся непосредственно в переменной
Ссылочные типы и производительность Размещаются в управляемой куче Содержат дополнительные поля: ссылка на объект-тип и индекс SyncBlockIndex Поля инициализируются нулем Создание объекта может повлечь сборку мусора
Значимые типы Определяются при помощи ключевого слова struct Являются наследниками System.ValueType : System.Object Не могут иметь наследников Могут реализовывать интерфейсы
Семантика копирования Ссылочные типы: копируется только ссылка. Несколько переменных могут указывать на один объект. Значимые типы. Производится почленное копирование. Одному объекту соответствует ровно одна переменная
Значимые типы Могут быть в упакованной (boxed) и неупакованной (unboxed) форме Наследуются от System.ValueType, который реализует правильно, но малоэффективно Equals и GetHashCode Переменная значимого типа не может быть nullом (хотя есть nullable типы) Метод Finalize не вызывается Желательно должны быть неизменяемыми
Размещение полей типа Автоматический Последовательный Явный using System; using System.Runtime.InteropServices; [StructLayout(LayoutKind.Auto)] internal struct SomeValType { Byte b; Int16 I; }
Упаковка значимых типов Требуется всегда, когда от значимого типа требуется поведение, описанное в базовом классе или интерфейсе. Например, при вызове методов базового класса или приведении к базовому типу или интерфейсу Распаковка – получение из упакованного объекта неупакованной его части. public class boxed { private T x; public boxed(T x) { this.x = x; } public override bool Equals(object o) { return x.Equals(o); } public T unbox() { return x; } // …. }
Упаковка и производительность Компилятор C# выполняет упаковку автоматически везде, где она требуется. С другой стороны, она подразумевает создание объектов ссылочного типа и копирование в них полей значимого типа, что может ударить по производительности
Упаковка и производительность public static void Main() { Int32 v = 5; Object o = v; v = 123; Console.WriteLine(v); // вызывается WriteLine(Int32) Console.WriteLine(, ); v = (Int32)o; Console.WriteLine(v); // отображается 123, 5 }
Изменение полей в упакованных типах посредством интерфейсов
Равенство и тождество объектов
Равенство объектов как оно должно быть
Сравнение объектов Тождественность Свойства сравнения рефлексивность: x.Equals(x) == true cимметричность: x.Equals(y) == y.Equals(x) транзитивность: x.Equals(y) && y.Equals(z) x.Equals(z) постоянство: если в сравниваемых значениях не произошло изменения, то результат сравнения должен остаться прежним
Сравнение объектов System.IEquatable -- typesafe интерфейс для сравнения объектов типа T Операторы == и != Интерфейсы IComparable и IComparable Операторы, =
Хеш-коды объектов В System.Object есть метод GetHashCode. Его надо переопределить всегда, когда переопределяется метод Equals Принципы реализации GetHashCode: -- равномерное распределение значений -- максимальная скорость -- должен основываться на неизменяемых полях объекта -- x.Equals(y) x.GetHashCode() == y.GetHashCode()
Хеш-коды объектов Реализация GetHashCode в System.Object возвращает id, уникальный для AppDomainа. Реализация GetHashCode в System.ValueType использует рефлексию для того, чтобы сформировать хеш-код объекта, основываясь на значениях его полей
Члены типа Константы Поля Конструкторы экземпляров Конструктор типа Методы Перегруженные операторы Операторы преобразования Свойства События Вложенные типы
Видимость типов Дружественные сборки
Видимость членов Верификацию доступа к членам выполняет JIT-компилятор При наследовании CLR позволяет повышать, но не понижать уровень доступа к члену
Статические классы Содержат только статические члены: поля, методы, свойства, события… Нельзя создать экземпляр статического класса Является прямым потомком System.Object Не может реализовывать никаких интерфейсов
Частичные классы Могут быть определены в нескольких файлах одной сборки, используя ключевое слово partial Используются в первую очередь для отделения сгенерированной автоматически части класса от рукописной.
Ключевые слова, влияющие на отношения «базовый тип-наследник»
Константы Идентификатор, который никогда не меняется Может быть только элементарного типа Кладется в метаданные модуля, и при использовании ее значение встраивается в IL код (при изменении значения константы необходимо перекомпилировать модули ее использующие) Нельзя получить адрес константы и передать ее по ссылке
Поля Поле – это член данных, который хранит экземпляр value-типа или ссылку на reference-тип Статические неизменяемые поля можно использовать вместо констант, если хочется использовать неэлементарные типы и чтобы при изменении значения поля не приходилось перекомпилировать код, его использующий Для изменения неизменяемого поля можно использовать рефлексию
Изменяемость полей