Ваш вопрос можно перефразировать как «Как мне построить компилятор, который поддерживает множественное наследование и работает на CLR».Если это действительно тот путь, по которому вы хотите пройти, я бы начал здесь и попытался бы прочитать материал VTable, о котором упоминает Брамм.
Существует также этот ТАК вопрос, который показывает, как более или менее MC ++ эмулирует множественное наследование, просто удерживая экземпляры базового класса в качестве членов экземпляров производного типа.Обратите внимание, однако, что в вашем случае вам придется решать проблему алмазов (наследуя от двух или более базовых классов, имеющих общий базовый класс) по-разному, применение этого решения вслепую вызовет трехкратный вызов A.Confirm()
.Чтобы изменить это, ваш компилятор должен сначала сгладить иерархию наследования, а затем разделить все методы, содержащие вызовы base, на несколько методов.Итак, что-то вроде этого:
public class A
{
public virtual void Confirm()
{
Console.Writeline("A");
}
}
public class B : A
{
public virtual void Confirm()
{
base.Confirm();
Console.Writeline("B");
}
protected void Confirm_Before1()
{
}
protected void Confirm_After1()
{
Console.WriteLine("B");
}
}
public class C : A
{
public virtual void Confirm()
{
Console.Writeline("C");
base.Confirm();
}
protected void Confirm_Before1()
{
Console.Writeline("C");
}
protected void Confirm_After1()
{
}
}
public class D : A
{
public virtual void Confirm()
{
Console.Writeline("D");
base.Confirm();
Console.Writeline("DD");
}
protected void Confirm_Before1()
{
Console.Writeline("D");
}
protected void Confirm_After1()
{
Console.WriteLine("DD");
}
}
public class E : A
{
private readonly B _baseB = new B();
private readonly C _baseC = new C();
private readonly D _baseD = new D();
public virtual void Confirm()
{
_baseB.Confirm_Before1();
_baseC.Confirm_Before1();
_baseD.Confirm_Before1();
base.Confirm();
_baseB.Confirm_After1();
_baseC.Confirm_After1();
_baseD.Confirm_After1();
}
}
Ваш гипотетический компилятор должен будет проанализировать иерархию наследования, найти все методы, доступные из вашего типа с множественным наследованием, разбить их на N + 1 методов, где N - это числоbase
вызывает их и вызывает их по порядку в вашем перегруженном методе.
Однако, если вы измените свой пример, все станет намного сложнее.Что если у A
есть дополнительный метод Foo
, B.Confirm()
был:
public virtual void Confirm()
{
base.Foo();
Confirm.WriteLine("B");
}
и C.Confirm()
был
public virtual void Confirm()
{
Confirm.WriteLine("C");
base.Foo();
}
Что вы ожидаете от E.Confirm()
?Будет ли он звонить Foo
один или два раза?А что, если было несколько вызовов на Foo
в B.Confirm()
, но не в C.Confirm()
?Я мало представляю, как Python справляется с этим, достаточно сказать, что простое изменение класса B
на
class B(A):
def Confirm(self):
super().Confirm()
print("B")
super().Confirm()
и вызов E.Confirm
приводит к
C
D
A
DD
B
C
D
A
DD
Это выглядитпросто сбивает с толку меня, что является частью того, почему MI такой сложный.
В любом случае, окончательный ответ таков: если вам нужно поведение Python-esque, вам придется реализовать компилятор, который ищет нескольконаследование тем или иным способом (скорее всего, с использованием атрибута) и преобразование кода, чтобы сделать именно то, что делает Python.Конкретное решение - далеко не только ответ на вопрос SO, но если у вас возникнут какие-то конкретные проблемы при реализации этой сумасшедшей идеи, не стесняйтесь задавать другую.
РЕДАКТИРОВАТЬ:
Как PSAЯ думаю, что я должен упомянуть: если это не просто забавное упражнение / мысленный эксперимент, который вы делаете, а скорее вы пытаетесь решить реальную проблему - это не тот путь.Перепроектируйте свою систему, чтобы не полагаться на MI, или, если вы любите Python MI, не используйте C #.