Содержание
object
(System.Object
) — окончательный базовый класс для всех типов. Любой тип может быть автоматически (скрыто) приведен к базовому классу (upcast) object
.
Эта особенность может быть очень полезна при создании универсальных хранилищ, например:
1 2 3 4 5 6 7 | public class Stack { int position; object[] data = new object[10]; public void Push (object o) { data[position++] = o; } public object Pop() { return data[--position]; } } |
Поскольку Stack
работает с типом object
, в него можно добавлять (Push
) и удалять (Pop
) экземпляры любого типа.
object
— ссылочный тип, но не смотря на это значимые типы также могут быть приведены к типу object
(и обратно из него). Чтобы сделать это возможным, CLR должна проделать ряд приготовлений, чтобы устранить различия между ссылочными и значимыми типами. Этот процесс называется приведение к объектному типу (boxing) и восстановление значения из объектного образа (unboxing).
Приведение к объектному типу (boxing) и восстановление значения из объектного образа (unboxing)
Приведение к объектному типу (boxing) — процесс приведения экземпляра значимого типа к ссылочному типу. Ссылочным типом в данном случае может быть либо класс object
, либо интерфейс. Восстановление значения из объектного образа (unboxing) — обратный процесс, приведение object
назад к изначальному значимому типу.
1 2 3 | int x = 9; object obj = x; // Boxing int y = (int)obj; // Unboxing |
Восстановление значения требует явного приведения, при этом проверяется, что указанный значимый тип соответствует реальному типу объекта, и если это не так выбрасывается InvalidCastException
.
1 2 3 4 5 6 | object obj = 9; // 9 - тип int long x = (long) obj; // InvalidCastException, т.к. int и long полностью не соотносятся long x = (int) obj; // А так допустимо object obj = 3.5; // 3.5 - тип double int x = (int) (double) obj; // x = 3, (double) выполняет восстановление значения, // (int) - приведение к типу int |
При приведении к объектному типу экземпляр значимого тип копируется в новый объект, а при восстановлении значения содержимое объекта копируется назад в экземпляр значимого типа.
1 2 3 4 | int i = 3; object boxed = i; i = 5; Console.WriteLine (boxed); // 3 |
Проверка типа
C# проверяет тип два раза: статически (во время компиляции) и во время выполнения программы. Статическая проверка типа позволяет компилятору проверить программу без ее запуска. Следующий пример не будет скомпилирован благодаря статической проверке типа:
1 | int x = "5"; |
Проверка типа во время выполнения выполняется средой CLR при приведении к типу производного класса (downcast) и при восстановлении значения (unboxing).
1 2 | object y = "5"; int z = (int) y; // Ошибка во время выполнения при downcast |
Метод GetType и оператор typeof
Проверка типа во время выполнения возможна благодаря тому, что каждый объект хранит маленький маркер типа. Этот маркер в свою очередь сам является объектом типа System.Type
. Есть два способа получить объект System.Type
:
- вызвать метод
GetType
у проверяемого экземпляра объекта (вычисляется во время выполнения) - использовать оператор
typeof
с именем типа (вычисляется статически при компиляции)
System.Type имеет свойства для таких вещей как имя типа, сборка, базовый тип и т.д., а также ряд методов.
1 2 3 4 5 | int x = 3; Console.Write (x.GetType().Name); // Int32 Console.Write (typeof(int).Name); // Int32 Console.Write (x.GetType().FullName); // System.Int32 Console.Write (x.GetType() == typeof(int)); // True |
Список членов типа 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).
1 2 3 4 | object x = 3; object y = 3; Console.WriteLine (x == y); // False Console.WriteLine (x.Equals (y)); // True |
Поскольку x
и y
приводятся к типу object
, компилятор использует объектный оператор ==
, который сравнивает объекты по ссылке (и поскольку x
и y
приведены к объектному типу, они являются двумя разными объектами, отдельно хранящимися в памяти, и поэтому не равны).
Однако виртуальный метод Equals
отсылает к методу Equals
типа Int32
, который сравнивает объекты по значению.
Статический метод object.Equals
просто вызывает виртуальный метод Equals
для первого аргумента, предварительно проверив что оба аргумента не равны null
.
1 2 3 | object x = null, y = 3; bool error = x.Equals (y); // Ошибка при выполнении bool ok = object.Equals (x, y); // Без ошибки вернет false |
Метод ReferenceEquals
принудительно сравнивает объекты по ссылке (это может быть удобно для ссылочных типов если оператор ==
перегружен и выполняет иное действие).
Метод GetHashCode
извлекает хэш-код, который может быть использован в словарях, основанных на хэш-таблицах (System.Collections.Generic.Dictionary
и System.Collections.Hashtable
).
Метод ToString
Метод ToString возвращает текстовое представление по умолчанию экземпляра типа. Этот метод переопределен для всех предопределенных типов.
1 2 | string s1 = 1.ToString(); // s1 = "1" string s2 = true.ToString(); // s2 = "True" |
1 | public override string ToString() { return "Foo"; } |