Здравствуйте, Jolly Roger, Вы писали:
JR>С другой стороны, тут есть ещё один момент, который я прошлой ночью упустил — рефлексия. (Ну очень спать хотелось ) Для неё необходимо, чтобы информация о всех членах класса, в том числе невиртуальных методах, была доступна в рантайм. В принципе, JIT может ей воспользоваться при необходимости. Но с другой стороны, ей-же может воспользоваться и C# компилятор, то есть такие вопросы можно вроде как разрешить на этапе компиляции в IL. Иначе у меня не получается непротиворечиво объяснить тот листинг, что я приводил здесь
. Ведь в методе Test нет никаких упоминаний BaseObj, однако в IL-листинге он присутствует. Это, по-моему, может означать только одно — C#-компилятор произвёл поиск метода вверх по иерархии и подставил в результирующий IL код его адрес, этот адрес мы и видим в виде метки BaseObj::Sum. Иначе у меня как-то не срастается
Я так понимаю, что компилятор и JIT-работают вместе. Компилятор может в такой ситуации определить метод какого класса будет вызван, но у JIT'а есть фукнции дополнительной проверки и разрешения конфликтных ситуаций. Samius вчера высказал мнение, что это сделано потому, что IL в принципе может быть кривым, ведь нет гарантий, что он не был создан вручную или каким-то другим компилятором, поэтому JIT должен делать свои проверки и по-возможности разруливать "косяки".
JR>А вот тот пример с дизассемблированием, правкой и повторной компиляцией с помощью ILasm — а что покажет ILDasm, если ему скормить результат работы ILAsm? Там сохранится внесённое вручную Employee::GetYearsEmployed, или опять оказывается исходная EmployeeBase::GetYearsEmployed?
Здравствуйте, vf, Вы писали:
vf>Судя повсему тот класс который указан в IL предназначен только для пользователя, для компилятора он не нужен и не несет никакой информации.
Здравствуйте, MozgC, Вы писали:
MC>В таком случае без перекомпиляции вызовется метод базового класса. Видимо jit просто берет метод указанный в IL и, если он не найден в указанном классе, то идет вверх и ищет где он. А в данном примере в IL останется вызов базового класса, jit увидит, что метод есть у указанного класса и не проверит, что метод уже переопределен в дочернем.
Похоже что, все таки отработает как положено, лениво проверять
, по мотивам первоисточника, я выразил свою мысль: что тип указаный в IL-коде после дисассемблера носит только информационный характер, и предназначен только для пользователя.
Здравствуйте, MozgC, Вы писали:
vf>>Судя повсему тот класс который указан в IL предназначен только для пользователя, для компилятора он не нужен и не несет никакой информации.
MC>Для JIT'а судя по всему все-таки нужен
Здравствуйте, vf, Вы писали:
MC>>В таком случае без перекомпиляции вызовется метод базового класса. Видимо jit просто берет метод указанный в IL и, если он не найден в указанном классе, то идет вверх и ищет где он. А в данном примере в IL останется вызов базового класса, jit увидит, что метод есть у указанного класса и не проверит, что метод уже переопределен в дочернем.
vf>Похоже что, все таки отработает как положено, лениво проверять
Здравствуйте, MozgC, Вы писали:
MC>Я так понимаю, что компилятор и JIT-работают вместе. Компилятор может в такой ситуации определить метод какого класса будет вызван, но у JIT'а есть фукнции дополнительной проверки и разрешения конфликтных ситуаций. Samius вчера высказал мнение, что это сделано потому, что IL в принципе может быть кривым, ведь нет гарантий, что он не был создан вручную или каким-то другим компилятором, поэтому JIT должен делать свои проверки и по-возможности разруливать "косяки".
Да, судя по всему так и есть.
JR>>А вот тот пример с дизассемблированием, правкой и повторной компиляцией с помощью ILasm — а что покажет ILDasm, если ему скормить результат работы ILAsm? Там сохранится внесённое вручную Employee::GetYearsEmployed, или опять оказывается исходная EmployeeBase::GetYearsEmployed?
MC>Ну, я же это написал в том свое посте:
Извиняюсь, вчера уже полусонный был, допустил ненимательность, а сегодня не посмотрел ещё раз.
Здравствуйте, vf, Вы писали:
vf>Покоя нет мне... как же так, выходит что здесь ошибка в описании?! Или я не правильно понял? vf>
That is, the method is chosen based on the runtime type of obj rather than the compile-time class visible in the method pointer.
Думаю, что неточное описание. Это справедливо для виртуальных функций, а для невиртуальных — не всегда, как показали наши опыты
Хотя, по поводу того, что если в отдельной сборке переопределить метод у дочернего класса и подменить сборку, после чего все равно вызовется метод базового класса, — тут можно выдать это за фичу. Т.е. клиент, когда писал программу, ожидал что вызовется метод базового класса, он не рассчитывал что может появиться метод у дочернего класса, т.к. метод не виртуальный. А тут ему подменивают сборку и поведение. Но все работает как и ожидал клиент при компиляции. Т.е. можно посмотреть на это с этой стороны
Здравствуйте, MozgC, Вы писали:
MC>Хотя, по поводу того, что если в отдельной сборке переопределить метод у дочернего класса и подменить сборку, после чего все равно вызовется метод базового класса, — тут можно выдать это за фичу. Т.е. клиент, когда писал программу, ожидал что вызовется метод базового класса, он не рассчитывал что может появиться метод у дочернего класса, т.к. метод не виртуальный. А тут ему подменивают сборку и поведение. Но все работает как и ожидал клиент при компиляции. Т.е. можно посмотреть на это с этой стороны
Да возможно...хотя и не однозначно. Как в описании callvirt мне кажется все таки логичнее. Интересно что:
1. если совсем убить метод в родителе, то получим MissingMethodException
2. а, если сделать метод в родителе абстрактным — тогда вызывается метод потомка
Это все без перекомпиляции самого приложения конечно.