Поскольку Int32 является типом значения, почему он наследует .ToString ()?

Это документы о .ToString(), по которым возник этот вопрос. Они заявляют:

Поскольку Object является базовым классом для всех ссылочных типов в .NET Framework, это поведение [.ToString ()] наследуется ссылочными типами, которые не переопределяют метод ToString.

Но далее говорится:

Например, базовые типы, такие как Char, Int32 и String, предоставляют реализации ToString.

Однако Int32 является структурой и, следовательно, должен быть типом значения.

Так что здесь происходит? Реализует ли Int32 свой собственный .ToString (), который не имеет ничего общего с Object?


person m.edmondson    schedule 16.11.2011    source источник
comment
Я почти уверен, что это связано с боксом.   -  person MBen    schedule 16.11.2011
comment
Форумы . asp.net/t/1694055.aspx/   -  person    schedule 16.11.2011
comment
@MBen Я почти уверен, что вопрос и ответ не имеют ничего общего с боксом.   -  person Ben Robinson    schedule 16.11.2011
comment
Похоже, вы не понимаете, как тип значения может наследовать от ссылочного типа, что немного похоже на то, что вы не понимаете, как вы можете поместить красную рамку в синюю - конечно, вы можете помещать только синие квадраты. внутри других синих коробок, верно? Нет, вы можете поместить красную рамку в синюю, и вы также можете получить тип значения из ссылочного типа. Это может помочь: blogs.msdn. ru / b / ericlippert / archive / 2011/09/19 /   -  person Eric Lippert    schedule 16.11.2011
comment
Обратите внимание, что в документации, которую вы цитируете, говорится, что Object является базовым классом для всех ссылочных типов в .NET Framework. Однако это НЕ означает, что все, что имеет Object в иерархии наследования, является ссылочным типом. (Все кошки относятся к классу Mammalia, но не все виды в классе Mammalia являются кошками.) Совершенно законно, чтобы тип значения наследовал от ссылочного типа, и фактически, все struct происходят от ValueType (сам по себе ссылочный тип), а ValueType происходит от Object.   -  person jason    schedule 16.11.2011


Ответы (6)


Int32 - это структура и, следовательно, тип значения. Но:

System.Object
   System.ValueType
      System.Int32

Int32 является производным от System.ValueType, а сам является производным от System.Object. И вуаля...

person Anja    schedule 16.11.2011
comment
Вы когда-нибудь видели объявление структуры вроде _1 _...? мне интересно, как они заставляют это компилироваться :) если вы когда-нибудь декомпилируете System.Int32, вы получите public struct Int32 : IComparable, IFormattable, IConvertible, IComparable<int>, IEquatable<int> ... но все еще имеете baseType _4 _... странно, не так ли? - person ; 16.11.2011
comment
Отлично, это помогло мне понять - есть ли что-то особенное в System.ValueType, что заставляет среду выполнения обрабатывать это по-другому? - person m.edmondson; 16.11.2011
comment
@ m.edmondson, это та часть, которую я никогда не понимал ... я полагаю это особенный clr ... я думаю, что книга спецификации .net-clr от Microsoft (что-то вроде это: amazon.de/Programming-Language-Covering-Microsoft-Development/) расскажет об этой магии :) - person ; 16.11.2011
comment
Думаю, было бы удобно, если бы @Jon мог подробнее рассказать об этом! - person m.edmondson; 16.11.2011
comment
@AndreasNiedermair: Что именно вас интересует? Уверяю вас, что в этом нет ничего волшебного; это прямой компилятор. - person Eric Lippert; 16.11.2011
comment
@Andreas Niedermair: Согласно спецификации, это не законно. В спецификации четко прописано, что вы не можете явным образом наследовать от System.ValueType и что есть специальное зарезервированное слово struct, которое выполняет это, и что когда вы используете его для пометки определения типа, вы можете перечислять только интерфейсы, которые реализует тип, но не базовый класс (опять же, он неявно является производным от System.ValueType). - person jason; 16.11.2011
comment
@EricLippert @ Джейсон все понял! ... ключевое слово struct подразумевает System.ValueType ... спасибо @Jason! - person ; 17.11.2011

Да, Int32 переопределяет _2 _..., хотя здесь это не имеет значения. Все типы наследуют члены object - вы можете всегда вызывать ToString(), вы можете всегда вызывать Equals и т. д. (ValueType переопределяет Equals и GetHashCode для вас , хотя вам почти всегда следует переопределять их дальше в структурах, чтобы обеспечить более эффективную реализацию.)

Обратите внимание, что вы можете очень легко переопределить методы самостоятельно:

public struct Foo
{
    public override string ToString()
    {
        return "some dummy text";
    }
}

Непонятно, какой аспект сбивает вас с толку (здесь задействовано довольно много разных областей). Если бы вы могли уточнить, мы могли бы решить конкретную проблему.

person Jon Skeet    schedule 16.11.2011
comment
Я думаю, его смущает тот факт, что типы значений ведут себя как типы значений, но наследуются от объекта, который является классом и, следовательно, ссылочным типом ... - person ; 16.11.2011
comment
@AndreasNiedermair: Более того, они наследуются от ValueType, который сам по себе является классом :) - person Jon Skeet; 16.11.2011
comment
юп, знай, просто хотел понять это очень прямо :) - person ; 16.11.2011
comment
Спасибо, Джон - именно ваша статья о типах значений и ссылок заставила меня задуматься об этом. Путаница заключается в заявлении Object is the base class of all reference types и, следовательно, наследует .ToString, так почему же Int32 также наследует это? - person m.edmondson; 16.11.2011
comment
Быть базовым классом для всех ссылочных типов не означает, что он также не может быть в иерархии наследования для всех типов значений. - person Domenic; 16.11.2011
comment
см. мой комментарий @ stackoverflow.com/questions/8152761/ - person ; 16.11.2011
comment
@ m.edmondson, объект типа значения см. здесь иерархия. - person John H; 16.11.2011
comment
@JonSkeet - Так есть ли что-то особенное в System.ValueType, что означает, что среда CLR обрабатывает его по-другому? - person m.edmondson; 16.11.2011
comment
@ m.edmondson: Да, CLR знает о System.ValueType и System.Enum. Это очень особенные типы. - person Jon Skeet; 16.11.2011

Возможно, вы замешаетесь из-за того, что не понимаете, что типы значений наследуются от Object? Вот граф наследования System.Object, System.ValueType, System.Int32 и MyNamespace.Customer, который, как предполагается, является вашим собственным классом. Я был ленив и не написал все общедоступные методы и интерфейсы Int32.

UML

ToString объявлен в Object, но отменяется как в ValueType, так и в Int32.

person Martin Liversage    schedule 16.11.2011

Документы неверны. И ссылочные типы, и типы значений наследуют это поведение от объекта (но помните, что не все в .NET является классом, производным от объекта).

Все (большинство?) Типов основных значений переопределяют ToString (), чтобы вернуть что-то более разумное, чем имя класса.

person Euro Micelli    schedule 16.11.2011
comment
Приведенная выше документация верна. Почему вы считаете это неправильным? - person Eric Lippert; 16.11.2011
comment
@ERic Lippert: если типы значений наследуются от ValueType, это может означать, что можно использовать типы значений везде, где можно использовать ValueType. Однако это не работает: ValueType удовлетворяет ограничению класса, но не ограничению структуры, тогда как типы значений удовлетворяют ограничению структуры, но не ограничению класса. Если присвоить структуру с изменяющимся интерфейсом (например, перечислитель List) переменной типа ValueType, результирующая переменная будет вести себя как изменяемый тип класса, а не как изменяемый тип значения. - person supercat; 17.12.2011
comment
@supercat: В вашем аргументе есть небольшая логическая ошибка. Если структура S наследуется от ValueType, тогда ожидается, что (1) все члены ValueType также являются членами S; это определение наследования. И (2) значение типа S может быть присвоено переменной типа ValueType (в данном случае посредством преобразования упаковки). Но это оба факта о экземплярах S. Нет требования, чтобы тип S можно было использовать везде, чтобы тип ValueType мог законно использоваться . - person Eric Lippert; 17.12.2011
comment
@supercat: подумайте об этом так: яблоко - это своего рода фрукт. Если у вас есть миска, в которой могут быть фрукты, тогда в этой миске может быть яблоко; яблоки совместимы с фруктами. У всех фруктов свой вкус; яблоки обладают этим свойством, потому что они фрукты. Яблоки наследуют свойства от фруктов. Но это не значит, что вы можете заменить слово яблоко везде, где появляется слово фрукт, и сохранить истинность предложения! Слово «фрукт» начинается с буквы «f», его нельзя заменить словом «яблоко» и сохранить его истинность. - person Eric Lippert; 17.12.2011
comment
@EricLippert: преобразование неупакованного типа значения в ValueType - это преобразование, изменяющее представление. Преобразование упакованного типа значения в ValueType сохраняет представление. На мой взгляд, это говорит о том, что упакованные типы значений фактически являются объектами типа класса, которые наследуются от ValueType, а неупакованные - нет. Вместо этого они неявно преобразуются в упакованные типы значений, которые наследуются от ValueType. Проблема в том, что запрос к JIT-коду, который будет работать с параметром, переменной или полем, производным от ValueType ... - person supercat; 17.12.2011
comment
@EricLippert: ... создаст код, который управляет сущностью напрямую, а не через ссылку на кучу. Когда я думаю об этом, я несколько впечатлен людьми .net 2.0, которым удалось заставить дженерики работать так же хорошо, как и они. Было бы интересно поразмышлять о том, как все могло бы работать, если бы существовали средства для объектов, ссылающихся на кучу, для демонстрации семантики значений (что означает, что копия могла бы быть не просто блит-версией, но должна была бы рекурсивно копировать любые вложенные ссылки на кучу, которые должны были иметь семантику значений), но это еще больше усложнило бы ситуацию. - person supercat; 17.12.2011
comment
@EricLippert: Я думаю, что моя самая большая путаница заключается в том, как описать тип того, что передается в параметр, чтобы отличить типы значений в штучной упаковке от типов реальных значений. Я склонен рассматривать переменные / поля / параметры типов значений как находящиеся за пределами системы типов. Рассмотрите возможность вызова bool f<T>(T bar) where T:IEnumerator<Integer> {return bar.MoveNext();} либо с переменной типа List.Enumerator ‹Integer›, либо с переменной типа IEnumerator ‹Integer›, которая содержит List.Enumerator ‹Integer›. Как бы вы описали тип экземпляра, переданного в bar в каждом случае? - person supercat; 17.12.2011
comment
@supercat: вы путаете наследование с совместимостью назначений. Наследование - это свойство типов, что члены базового типа также являются членами производного типа; наследование не имеет ничего общего с тем, как биты выглядят в памяти. Распакованный тип значения несовместим по присваиванию с переменной типа ValueType, но тип значения по-прежнему наследует все члены своего базового класса. - person Eric Lippert; 17.12.2011
comment
@EricLippert: значение без упаковки может быть присвоено одному из ValueType без явного приведения типа (но не наоборот). - person supercat; 21.12.2011

Я думаю, что краткий ответ на ваш вопрос заключается в том, что типы значений наследуются от System.ValueType и это, в свою очередь, наследуется от объекта.

person Ben Robinson    schedule 16.11.2011

Каждый struct имеет наследование от System.ValueType класса (не разрешено), которое выполняется исключительно компилятором. Все struct имеют методы из ValueType базового класса, который унаследован от класса Object, что дает нам доступ к ToString() и всем остальным.

Несмотря на то, что ValueType унаследован от класса Object, у него есть особая реализация переопределений.

person Abdul Munim    schedule 16.11.2011