Dmitry
Помогающий
Offline
|
|
« : 22-10-2009 15:11 » |
|
Привет всем, Изучаю шарп, в этой теме буду задавать некоторые вопросы, а вы по возможности пытайтесь на них отвечать. Вот такая конструкция работает object obj = .... int? my = obj as int?; Почему мы не можем распаковать так? int? my = obj as int; Да, по требованиям компилятора оба операнда должны быть ссылочными или nullable типами. Но ведь тут всё замечательно - если в obj было упаковано число, int неявно приводится к Nullable<int>, иначе ему присваивается null. Хм, можно так: int myInt = 100; object obj = myInt; int? my = obj as int?; Сообщения не правятся... монолог будет. Т.е. получается, что как бы тип int - производный от nullable<int> (и вообще приводить int к int? можно неявно) . Но ведь это структуры, для них нет наследования?
|
|
« Последнее редактирование: 22-10-2009 16:00 от RXL »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #1 : 22-10-2009 17:46 » |
|
Почему мы не можем распаковать так? int? my = obj as int;
Оператор as использует RTTI для определения типа значения, хранящегося в переменной (возможно, другого, более общего типа). Для value-типов RTTI отсутствует, поэтому оператор работать не может. P.S. А вообще, как говорится, "потому что гладиолус!" Раз нельзя так использовать оператор, значит нельзя.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dmitry
Помогающий
Offline
|
|
« Ответ #2 : 22-10-2009 18:22 » |
|
Оператор as использует RTTI для определения типа значения, хранящегося в переменной (возможно, другого, более общего типа). Для value-типов RTTI отсутствует, поэтому оператор работать не может.
А как же тогда В общем, я понял. Оператор as возвращает тип второго операнда. Естественно, он должен поддерживать null-значение. RXL, странный ход. По-моему, гораздо чаще новички не могут с первого раза толково сформулировать вопрос, и пытаются отыскать кнопку редактирования.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #3 : 22-10-2009 20:03 » |
|
GetType возвращает объект типа Type, описывающий некий тип. Относится ли этот тип к переменной или к хранящемуся в ней значению, прямо зависит от наличия или отсутствия RTTI. В общем, я понял. Оператор as возвращает тип второго операнда. Оператор as возвращает не тип, а значение, тип которого сводится (или соответствует) заданному, либо null, если соответствие отсутствует. Тип возвращает GetType.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dmitry
Помогающий
Offline
|
|
« Ответ #4 : 22-10-2009 20:35 » |
|
Оператор as возвращает не тип, а значение, тип которого сводится (или соответствует) заданному, либо null, если соответствие отсутствует. Да, я это и имел в виду, неправильно написал. Конечно, as не Type возвращает. В случае, если соответствие отсутствует, возвращается тоже значение заданного типа, но оно равно null. Поэтому "int? my = obj as int" и не работает - значению типа int нельзя присвоить null, а вот int? - можно. Из мсдн: expression as type эквивалентно expression is type ? (type)expression : (type)null
|
|
|
Записан
|
|
|
|
RXL
Технический
Администратор
Offline
Пол:
|
|
« Ответ #5 : 22-10-2009 21:16 » |
|
RXL, странный ход. По-моему, гораздо чаще новички не могут с первого раза толково сформулировать вопрос, и пытаются отыскать кнопку редактирования. Offtopic: Как говорится - поадминь с мое... Кривизну может отредактировать модератор, а стертое может не остаться даже в бекапах.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
Dmitry
Помогающий
Offline
|
|
« Ответ #6 : 27-10-2009 06:58 » |
|
Перешёл на Рихтера, до этого читал сначала Троелсена, потом Нейгела и Ко. Жалею, что сразу с Рихтера не начал. У него хоть и основы, но гораздо толковее написано. Пока вопрос остался - как CLR определяет связь между производными типами? В объектах-типах, которые хранят информацию о типах, об этом же нет никаких данных?
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #7 : 27-10-2009 08:28 » |
|
Пока вопрос остался - как CLR определяет связь между производными типами? См. в сторону System.Reflections.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dmitry
Помогающий
Offline
|
|
« Ответ #8 : 28-10-2009 07:31 » |
|
См. в сторону System.Reflections.
Свойство типа BaseType возвращает базовый тип. Но мне интересно, как это реализовано. Подозреваю, что через метаданные. Ещё интересно, как определяется тип ссылки, через которую мы вызываем невиртуальный метод. Если метод виртуальный то цепочка действий более менее понятна - разыменовывание указателя, получение через указатель на объект-тип объекта Type, который и содержит таблицу методов.
|
|
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #9 : 28-10-2009 08:51 » |
|
Свойство типа BaseType возвращает базовый тип. Но мне интересно, как это реализовано. Вопрос совершенно непонятный. Связь между классами определяет компилятор в процессе компиляции. Ты хочешь узнать, как реализован компилятор? Что ты подразумеваешь под "метаданными", и почему тебе становится легче, когда ты начинаешь подозревать именно их? Ещё интересно, как определяется тип ссылки, через которую мы вызываем невиртуальный метод. Если метод виртуальный то цепочка действий более менее понятна - разыменовывание указателя, получение через указатель на объект-тип объекта Type, который и содержит таблицу методов. Белые люди так не делают. В runtime для собственных внутренних нужд механизм reflections не используется, так как очень медленный. Компилятор для объекта создаёт таблицу виртуальных методов, в которой хранятся указатели на виртуальные методы. Когда класс унаследован от другого, в процессе создания объекта сначала срабатывает конструктор (по умолчанию, если не задан программистом явно) базового класса, который заполняет таблицу для базового класса, затем конструктор производного класса перезаписывает указатели на те методы, которые переопределены в нём самом. В результате при обращении к объекту через переменную любого класса (хоть базового, хоть производного) всё равно вызываются методы производного класса. Никакого "типа ссылки" нету, потому что в языке нет типа "виртуальный метод".
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
Dmitry
Помогающий
Offline
|
|
« Ответ #10 : 29-10-2009 06:35 » |
|
Вопрос совершенно непонятный. Связь между классами определяет компилятор в процессе компиляции. Ты хочешь узнать, как реализован компилятор?
Да, что-то меня не туда повело Во время выполнения программы ведь по сути не существует никаких классов. Для невиртуальных методов компилятор на основании типа переменной, через которую мы делаем вызов, встраивает в код вызов конкретной функции. По поводу виртуальных методов. То, что я описал - написано у Рихтера. Что каждый объект в куче дополняется указателем на объект-тип и индексом для синхронизации. Объект-тип представляет собой данные о типе (классе), статические поля, таблицу методов. Я правильно теперь понял - этот объект-тип есть экземпляр класса Type (точнее Runtimetype, но сейчас это не важно), ссылку на который можно получить ч-з GetType или typeof, и используется он только в рефлексии и для RTTI. А при вызове виртуальных методов используется скрытый указатель (который есть в объекте каждого класса, реализующего виртуальные методы) на таблицу в.м. Примерно так? У тебя странно написано, что таблица в.м. заполняется конструкторами. Разве она не заполняется полностью для каждого класса компилятором?
|
|
« Последнее редактирование: 29-10-2009 09:01 от Dmitry »
|
Записан
|
|
|
|
Dimka
Деятель
Команда клуба
Offline
Пол:
|
|
« Ответ #11 : 29-10-2009 15:13 » |
|
То, что я описал - написано у Рихтера. Что каждый объект в куче дополняется указателем на объект-тип и индексом для синхронизации. Объект-тип представляет собой данные о типе (классе), статические поля, таблицу методов. Я правильно теперь понял - этот объект-тип есть экземпляр класса Type (точнее Runtimetype, но сейчас это не важно), ссылку на который можно получить ч-з GetType или typeof, и используется он только в рефлексии и для RTTI. А при вызове виртуальных методов используется скрытый указатель (который есть в объекте каждого класса, реализующего виртуальные методы) на таблицу в.м. Примерно так?
У тебя странно написано, что таблица в.м. заполняется конструкторами. Разве она не заполняется полностью для каждого класса компилятором? То, что я сказал, относится не к .NET и C#. Это общий принцип работы виртуальных методов. Лично меня тонкости реализации этого принципа в .NET не интересовали и не интересуют. Суть состоит в том, что при позднем связывании у объекта есть таблица виртуальных методов, из которой он извлекает нужный метод. Заполняет ли её компилятор в точке создания объекта, или она вычисляется в runtime - для меня дело десятое.
|
|
|
Записан
|
Программировать - значит понимать (К. Нюгард) Невывернутое лучше, чем вправленное (М. Аврелий) Многие готовы скорее умереть, чем подумать (Б. Рассел)
|
|
|
|