Speak.Me Учить иностранные слова

C#: тип объект (Object Type)

object (System.Object) — окончательный базовый класс для всех типов. Любой тип может быть автоматически (скрыто) приведен к базовому классу (upcast) object.

Эта особенность может быть очень полезна при создании универсальных хранилищ, например:

Поскольку Stack работает с типом object, в него можно добавлять (Push) и удалять (Pop) экземпляры любого типа.

object — ссылочный тип, но не смотря на это значимые типы также могут быть приведены к типу object (и обратно из него). Чтобы сделать это возможным, CLR должна проделать ряд приготовлений, чтобы устранить различия между ссылочными и значимыми типами. Этот процесс называется приведение к объектному типу (boxing) и восстановление значения из объектного образа (unboxing).

Приведение к объектному типу (boxing) и восстановление значения из объектного образа (unboxing)

Приведение к объектному типу (boxing) — процесс приведения экземпляра значимого типа к ссылочному типу. Ссылочным типом в данном случае может быть либо класс object, либо интерфейс. Восстановление значения из объектного образа (unboxing) — обратный процесс, приведение object назад к изначальному значимому типу.

Восстановление значения требует явного приведения, при этом проверяется, что указанный значимый тип соответствует реальному типу объекта, и если это не так выбрасывается InvalidCastException.

При приведении к объектному типу экземпляр значимого тип копируется в новый объект, а при восстановлении значения содержимое объекта копируется назад в экземпляр значимого типа.

Проверка типа

C# проверяет тип два раза: статически (во время компиляции) и во время выполнения программы. Статическая проверка типа позволяет компилятору проверить программу без ее запуска. Следующий пример не будет скомпилирован благодаря статической проверке типа:

Проверка типа во время выполнения выполняется средой CLR при приведении к типу производного класса (downcast) и при восстановлении значения (unboxing).

Метод GetType и оператор typeof

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

  • вызвать метод GetType у проверяемого экземпляра объекта (вычисляется во время выполнения)
  • использовать оператор typeof с именем типа (вычисляется статически при компиляции)

System.Type имеет свойства для таких вещей как имя типа, сборка, базовый тип и т.д., а также ряд методов.

Список членов типа object

  • public extern Type GetType();
  • public virtual bool Equals (object obj);
  • public static bool Equals (object objA, object objB);
  • public static bool ReferenceEquals (object objA, object objB);
  • public virtual int GetHashCode();
  • public virtual string ToString();
  • protected override void Finalize();
  • protected extern object MemberwiseClone();

Equals, ReferenceEquals и GetHashCode

Метод класса object Equals схож с оператором ==, за исключением того, что Equals виртуальный (virtual), а == статический (static).

Поскольку x и y приводятся к типу object, компилятор использует объектный оператор ==, который сравнивает объекты по ссылке (и поскольку x и y приведены к объектному типу, они являются двумя разными объектами, отдельно хранящимися в памяти, и поэтому не равны).

Однако виртуальный метод Equals отсылает к методу Equals типа Int32, который сравнивает объекты по значению.

Статический метод object.Equals просто вызывает виртуальный метод Equals для первого аргумента, предварительно проверив что оба аргумента не равны null.

Метод ReferenceEquals принудительно сравнивает объекты по ссылке (это может быть удобно для ссылочных типов если оператор == перегружен и выполняет иное действие).

Метод GetHashCode извлекает хэш-код, который может быть использован в словарях, основанных на хэш-таблицах (System.Collections.Generic.Dictionary и System.Collections.Hashtable).

Метод ToString

Метод ToString возвращает текстовое представление по умолчанию экземпляра типа. Этот метод переопределен для всех предопределенных типов.

Для пользовательских типов он также может быт переопределен: