Use a reflection para invocar um método base substituído

Como usar reflection chamar um método base que é substituído pela class derivada?

class Base { public virtual void Foo() { Console.WriteLine("Base"); } } class Derived : Base { public override void Foo() { Console.WriteLine("Derived"); } } public static void Main() { Derived d = new Derived(); typeof(Base).GetMethod("Foo").Invoke(d, null); Console.ReadLine(); } 

Este código sempre mostra “Derivado” …

Você não pode fazer isso, mesmo com reflection. O polymorphism no C # na verdade garante que o Derived.Foo() sempre será chamado, mesmo em uma instância de Derived cast de volta à sua class base.

A única maneira de chamar Base.Foo() de uma instância Derived é torná-la explicitamente acessível a partir da class Derived :

 class Derived : Base { public override void Foo() { Console.WriteLine("Derived"); } public void BaseFoo() { base.Foo(); } } 

Mesmo que a resposta atual já seja aceita, é realmente possível sem ter que alterar a class original usando um método dynamic como este:

  static void Main(string[] args) { Derived foo = new Derived(); foo.Foo(); MethodInfo method = typeof(Base).GetMethod("Foo"); DynamicMethod dm = new DynamicMethod("BaseFoo", null, new Type[] { typeof(Derived) }, typeof(Derived)); ILGenerator gen = dm.GetILGenerator(); gen.Emit(OpCodes.Ldarg_1); gen.Emit(OpCodes.Call, method); gen.Emit(OpCodes.Ret); var BaseFoo = (Action)dm.CreateDelegate(typeof(Action)); BaseFoo(foo); Console.ReadKey(); } 

como você pode ver, ainda é relativamente simples de fazer

Depois de muito tempo, finalmente encontrei uma solução melhor que DynamicMethod:

 class CallOverride { public static void Test() { var obj = new Override(); var method = typeof(object).GetMethod("ToString"); var ftn = method.MethodHandle.GetFunctionPointer(); var func = (Func)Activator.CreateInstance(typeof(Func), obj, ftn); Console.WriteLine(func()); } } class Override { public override string ToString() { return "Nope"; } } 

Esta solução usa a assinatura de construtor padrão do delegado:

 public Delegate(object target, IntPtr ftn) 

em que target é a instância de destino e ftn é o ponteiro de function. Ele invoca diretamente com o ponteiro de function do método base, portanto, o delegado apontará para o método base real, não o método substituído.

Reflexão permite que você veja que o object d tem um método “Foo” e também para invocá-lo.

No entanto, esse método é um método virtual e é por isso que você está obtendo a implementação desse método por uma class Derived, pois é o que d é (além de também ser convertível em uma Base).

Não existe uma maneira [direta] de invocar os methods virtuais da base a partir de um object derivado.
Como mostrado em Frederic Hamidi, o método da class Base pode ser exposto pela class Derived (sob um nome diferente), mas isso não está realmente invocando o método da Base, ele está invocando um método da class Derived que por acaso chama a base método.

Embora essa abordagem de ter a class Derived fornecendo um “proxy” para o método da class Base, em última análise, faz o que você pede, provavelmente é uma má idéia fazer isso: provavelmente há uma falha no design do seu modelo de object: seria um caso de uso bastante estranho …

O que você está vendo é o comportamento polimórfico que é por design. Quando você substitui um método virtual, invocar esse método na class substituída chama a implementação da class descendente do VMT.

Qual é o seu caso de uso, para ser honesto isso cheira um pouco como um problema de design.

Talvez Kii estivesse procurando por algo assim

 class Base { public virtual void Foo() { Console.WriteLine("Base"); } } class Derived : Base { // Change virtual with new // public override void Foo() { Console.WriteLine("Derived"); } public new void Foo() { Console.WriteLine("Derived"); } } static void Main(string[] args) { Derived d = new Derived(); d.Foo();// Output: Derived typeof(Base).GetMethod("Foo").Invoke(d, null);// Output: Base // Or you can cast ((Base)d).Foo();// Output: base Console.ReadLine(); } 
 Base b = (Base)d; Console.WriteLine(b.GetType()); //output:Derived 

1) A transmissão não pode alterar seu tipo de class.

 class Derived : Base { public override void Foo() { Console.WriteLine("Derived"); } public Base getBase() { return base; //compiler invalid } } 

2) Acima são inválidos, porque você nunca criou nenhuma instância do object Base quando criou a instância do object Derived . Você criou o object de instância da Derived class que herdou da Base class . Espero que isso explique porque você não pode invocar a function base com o object derivado