Подтвердить что ты не робот

Интерфейсы выводятся из System.Object? С# spec говорит "да", Эрик говорит "нет", реальность говорит "нет"

Вопрос прост и задан в названии.

С# 4.0 Спецификация говорит: (§4.2.2)

Тип класса объекта - это конечная базовый класс всех других типов. каждый введите С# прямо или косвенно происходит от типа класса объекта.

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

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

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

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

True

Значит, неправильно или что? Кому верить?

4b9b3361

Ответ 1

Это не такой простой вопрос, как вы думаете:)

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

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

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

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

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

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

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

  • От любого ссылочного типа до object и dynamic.

Ответ 2

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

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

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

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

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

Я лично предпочитаю думать, что объект не является "базовым типом" любого интерфейса и что члены объекта не наследуются интерфейсом. То, что вы можете называть их на экземпляре интерфейса, больше похоже на предоставленную вам компилятором любезность, так что вам не нужно вставлять приведение к объекту.

Ответ 3

Типы интерфейсов не наследуются от Object, но места хранения типов интерфейсов содержат ссылки на объекты класса, которые (если не null) гарантированно наследуются от 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, но переменная типа, ограниченная интерфейсом, может содержать ссылку или кучу полей.