2010-07-13 2 views
30

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

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

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

Eric Lippert says: типы

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

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

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

Правда

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

+1

«Каждый тип в C# ...», ну, я знаю, указатели не выводятся непосредственно из System.Object; так это пример случая «косвенно вытекает» или указатели не являются типом? – codekaizen

+0

@codekaizen Указатели являются отдельной темой. Они являются инопланетянами в мире .net, поэтому они не вписываются в основные концепции ОО. – Andrey

+0

@codekaizen от Eric «Небезопасные типы указателей явно не соответствуют нормальным правилам для языка». – Andrey

ответ

30

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

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

совпадению, я над головой разговор между Нилом Gafter и Эриком в НДЦ обсуждал именно этот вопрос ...

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

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

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

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

Эталонные Неявные являются:

  • Из любого эталонного типа к object и dynamic.
+0

Все, что реализует интерфейс (классы или структуры), будет выводиться из 'object'. Я не знаю, какие другие типы объектов (например, указатели) могут реализовывать интерфейсы. –

+0

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

+0

Я не могу понять разницу между * вывести * и * иметь эффективный базовый тип *. Даже если декларация класса и интерфейса выглядит очень похоже, они существенно отличаются, интерфейс - это просто контракт. Так как в .net ни один класс не может быть получен из чего-то другого, кроме Object, все ссылки на интерфейс могут быть переданы объекту. но это не значит для меня, что они фактически происходят от объекта. – Andrey

27

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

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

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

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

.

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

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

+0

C++ имеет такое же количество видов наследования, что и C# - два. – Puppy

+7

@DeadMG: C++ имеет общедоступное, частное и защищенное наследование, которое C# не имеет - C# имеет только публичное наследование классов. C++ имеет «виртуальное наследование», которое C# не делает. C++ имеет множественное наследование, которое C# не делает. –

2

Типы интерфейсов не наследуются от 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 's государственных и частных полей.Второй вызов требует вещи, которая происходит от Object, поэтому она генерирует новый экземпляр объекта кучи типа SimplePoint, который содержит все общедоступные и частные поля значения типа SimplePoint и загружает все эти поля с соответствующими значениями от myPoint и передает ссылку на этот объект.

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

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

+0

Первый вызов * делает * передается вещь, которая происходит от 'object': например, вы можете называть' ToString() 'на нем. – svick

+0

@svick: можно только называть «ToString» непосредственно на типах значений, которые определяют их собственную реализацию этого метода; если вы пишете '3.ToString();', он не будет выполняться как виртуальный вызов 'Object.ToString(), а просто будет выполняться как прямой вызов метода ToString(), который определенный для 'Int32'; такой вызов разрешен не потому, что 'Int32' происходит от' Object', а потому, что 'Int32' определяет свой собственный метод ToString(). Вызов 'ToString' на тип значения, который не определяет его собственную версию, заставит систему создать новый экземпляр объекта кучи, который ... – supercat

+0

... содержит данные, скопированные из типа значения (и который выводится из' Object'), а затем вызовет 'ToString'. Это происходит потому, что тип unboxed value может быть конвертирован в объект. Некоторые люди пытаются притвориться, что коробки и распакованные структуры одного типа. Это правда, что они описываются одним и тем же экземпляром 'Type', но, учитывая их различное поведение, я считаю более полезным рассматривать их как разные типы. – supercat