Не всё наследуется от object

Я слышу много мифов о C#. Обычно в мифах есть крупица истины, например «типы-значения всегда размещаются на стеке». Если вы замените «всегда» на «иногда», то некорректное мифическое утверждение станет корректным.

Миф, который я слышу особенно часто – «в C# все типы наследуются от object». Неправда!

Во-первых, никакие типы-указатели ни унаследованы от object, ни совместимы с ним по присваиванию. Небезопасные типы-указатели явно находятся за пределами обычных правил типизации нашего языка. (Если вы хотите трактовать указатель как тип-значение, то сконвертируйте его в System.IntPtr, и можете использовать его как значение.) Мы отложим типы-указатели в сторону до конца этой дискуссии.

Очень много типов наследуются от object. Все типы-значения, включая перечислимые (enum) и nullable типы, наследуются от object. Все классы, массивы и делегаты наследуются от object.

Все они – «конкретные» типы; всякий экземпляр объекта, который вы реально встретите в природе будет либо null, либо классом, делегатом, массивом, структурой, перечислимым, или nullable типом-значением. Так что будет корректно, хоть и тавтологически, говорить, что все экземпляры объектов наследуются от object. Но миф не в этом; миф заявляет, что все типы наследуются от object.

Типы – интерфейсы, не являясь классами, от object не наследуются. Они все могут быть приведены к object, конечно же, потому, что мы знаем, что во время исполнения экземпляр будет иметь конкретный тип. Но интерфейсы наследуются только от других интерфейсов, а object – это не интерфейс.

«Открытые» типы-параметры также не наследуются от object. Они, конечно же, типы. Вы можете объявить поле, тип которого взят из параметра. А поскольку обобщённые типы и методы во время исполнения используются исключительно будучи «сконструированными» с «конкретными» типами аргументов, типы-параметры всегда можно привести к object. (Вот почему вы не можете использовать IEnumerable<void*> – мы требуем, чтобы типы-аргументы были приводимы к object.) Типы-параметры не наследуются ни от чего; у них есть «эффективный базовый класс» - такой, что от типов-аргументов требуется наследоваться от эффективного базового класса, но сами они ни от чего не «унаследованы».

Простой способ исправить этот миф – заменить «наследуются от» на «приводимы к», и проигнорировать типы-укзатели: каждый тип в C#, кроме указателей, приводим к object.

оригинал статьи