Интерфейсы являются производными от System.Object?C # spec говорит да, Эрик говорит нет, реальность говорит нет - PullRequest
32 голосов
/ 13 июля 2010

Вопрос прост и задается в заголовке.

C # 4.0 Спецификация гласит: (§4.2.2)

Тип класса объекта является окончательным базовым классом для всех остальныхтипы.Каждый тип в C # прямо или косвенно происходит от типа класса объекта.

Эрик Липперт говорит: :

Типы интерфейса, не являющиеся классами, являютсяне получен из объекта.

Реальность говорит:

Type t = typeof(ICloneable).BaseType;
Console.WriteLine(t == null);

Верно

Так что спецификация неверна или что?Кому верить?

Ответы [ 3 ]

32 голосов
/ 13 июля 2010

Это не такой простой вопрос, как вы могли бы подумать:)

Интерфейсы не получают из object, но вы можете вызывать членов object на них. Таким образом, вы можете вызвать ToString() для выражения, которое имеет тип времени компиляции IDisposable, например.

По совпадению, я обсуждаю этот момент между Нилом Гафтером и Эриком в НЦД, обсуждая именно этот момент ...

К сожалению, раздел 4.2.2 спецификации слишком упрощен. Надеюсь, Мадс и Эрик исправят это в будущем выпуске - я пришлю им письмо, чтобы убедиться, что они увидят этот вопрос.

Я также изо всех сил пытаюсь найти что-то в спецификации, чтобы поддержать оставшуюся часть этого ответа. Раздел 3.4.5 спецификации C # 4 подходит как можно ближе:

Члены интерфейса - это члены, объявленные в интерфейсе и во всех базовых интерфейсах интерфейса. Члены класса object, строго говоря, не являются членами какого-либо интерфейса (13.2). Однако члены класса object доступны через поиск членов в любом типе интерфейса (7.4).

Преобразование из типа интерфейса в object описано в разделе 6.1.6:

Неявные ссылочные преобразования:

  • От любого ссылочного типа до object и dynamic.
29 голосов
/ 14 июля 2010

Джон находится (как обычно) на месте.Это не так просто, как вы думаете!

Спецификация нечеткая и слегка противоречивая.В этом конкретном случае, вероятно, лучше немного прищуриться и понять суть того, что спецификация означает для передачи , а не узко разбирать ее для точных определений.

Простой фактДело в том, что в объектно-ориентированном программировании термин «наследование» очень часто используется.(Кажется, я помню, что в C ++ есть шесть различных типов наследования, хотя мне было бы сложно назвать их всех в кратчайшие сроки.)

Если бы у меня были мои барабанщики, тогда спецификация C # явно вызывала быразница между наследованием и реализацией интерфейса .Наследование - это * метод совместного использования кода для типов классов (и делегатов) и структур (и перечислений) "; его механизм состоит в том, что все наследуемые члены базового типа становятся членами производного типа .В отличие от реализации интерфейса , которая является требованием, чтобы тип реализации имел определенный набор открытых членов . Эти две вещи кажутся мне концептуально очень разными, одна из них касается совместного использования существующихчлены , а другой - о , требующем определенных членов .

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

Лично я предпочитаю думать, что объект не «базовый тип»любой интерфейс, и что члены объекта не наследуются интерфейсом. Вы можете вызывать их наэкземпляр интерфейса больше похож на вежливость, предоставленную вам компилятором, так что вам не нужно вставлять приведение к объекту там.

2 голосов
/ 04 февраля 2013

Типы интерфейса не наследуются от Object, но места хранения типов интерфейса содержат ссылки на объекты типа класса, которые (если не ноль) гарантированно наследуют от System.Object.

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

public struct SimplePoint {public int x,y;}

и у меня есть два метода

public doSomethingWithPoint(SimplePoint pt) ...
public doSomethingWithObject(Object it) ...

и вызывайте каждый метод:

SimplePoint myPoint = ...;
doSomethingWithPoint(myPoint);
dosomethingWithObject(myPoint);

Первый вызов не передает то, что происходит от Object. Вместо этого он передает содержимое всех открытых и закрытых полей SimplePoint. Второму вызову нужна вещь, которая происходит от Object, поэтому он генерирует новый экземпляр объекта кучи типа SimplePoint, который содержит все открытые и закрытые поля типа-значения SimplePoint, и загружает все эти поля с помощью соответствующие значения из myPoint и передает ссылку на этот объект.

Обратите внимание, что тип SimplePoint на самом деле описывает два разных вида вещей: набор полей (то есть тип значения) и тип объекта кучи. Какое значение применимо, зависит от контекста, в котором используется тип.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...