У меня от этого мозг ломается. В моей картине мира виртуальной функция Test должна быть только в классе M.
using System;
class program
{
static void Main(string[] args)
{
int sum = 0;
sum += new Base1().Test();
sum += new Base2().Test();
Console.WriteLine(sum);
}
}
class Base1
{
public int Test()
{
var m = typeof(Base1).GetMethod(nameof(Test));
return m.IsVirtual ? 1 : 0;
}
}
class Base2
{
public int Test()
{
var m = typeof(Base2).GetMethod(nameof(Test));
return m.IsVirtual ? 1 : 0;
}
}
interface I { int Test(); }
class M : Base2, I { }
Что надо сделать, чтобы на экран был выведен 0 ? (Не меняя исходного кода)
_>А так поменяйте условие на с m.IsVirtual на (m.IsVirtual && !m.IsFinal)
Мне не надо узнавать, является ли метод overrideable.
Мне нужно, чтобы одинаково выглядящий код не менял своё поведение от того, что кто-то где-то дописал интерфейс.
Здравствуйте, Arsen.Shnurkov, Вы писали:
AS>Мне нужно, чтобы одинаково выглядящий код не менял своё поведение от того, что кто-то где-то дописал интерфейс.
Навесить свой [NonVirtualAttribute] и convention test на сборку.
Здравствуйте, Arsen.Shnurkov, Вы писали:
AS>Мне нужно, чтобы одинаково выглядящий код не менял своё поведение от того, что кто-то где-то дописал интерфейс.
А в чем проблема, что у вас из-за этого бинарная совместимость ломается?
Здравствуйте, Arsen.Shnurkov, Вы писали:
AS>У меня от этого мозг ломается. В моей картине мира виртуальной функция Test должна быть только в классе M.
Это видимо оптимизация компилятора. Похоже, что он просто экономит слоты в таблице виртуальных методов. Т.е. метод Base2.Test, доступный в исходниках, автоматечески помечается sealed virtual и его слот будет использоваться во всех его наследниках, неявно реализующих интерфейс I или любой другой интерфейс с методом Test нужной сигнатуры.
Явная реализация I.Test в классе M приводит к желамому 0 в выхлопе.
1) можно ли её отключить?
(UPD: SO, MSDN не помогает, pragma тоже)
2) все ли компиляторы должны так делать (т.е. написано ли это в какой-нибудь спецификации, или это Undefined Behaviour)?
3) как эта конкретная оптимизация называется на английском языке, чтобы её искать в гугле
UPD2:
C# compiler does not get involved at this level. The Entire type model, inheritance, interface implementation etc. is actually handled by the CLR more specifically the CTS (Common Type System). .NET compilers mostly just generate IL code that represents intent which is later executed by the CLR where all Vtable handling etc. is taken care of.
Virtual stub dispatching (VSD) is the technique of using stubs for virtual method invocations instead of the traditional virtual method table.
Здравствуйте, Arsen.Shnurkov, Вы писали:
AS>У меня от этого мозг ломается. В моей картине мира виртуальной функция Test должна быть только в классе M.
По-моему, Вы мешаете кислое с длинным. Семантика virtual в .Net немного отличается от семантики в C++ (т.е. де-факто там 2 виртуальных метода, которые ведут себя, как один не-виртуальный, ибо друг с другом не связаны). Попробуйте переформулировать свой test case, чтобы там проверялось поведение методов, а не m.IsVirtual. Тогда все быстро встанет на свои места.
Здравствуйте, Arsen.Shnurkov, Вы писали:
AS>Чудесно! AS>1) можно ли её отключить?
Она и так отключена.
В байткоде есть разные коды операций — непосредственного вызова метода или виртуального (Call и Callvirt).
Т.е. суть в том, что виртуальный метод можно звать как обычный — не через таблицу.
Посмотри в ассемблере, как был вызван код — напрямую или через таблицу виртуальных ф-ий.