Utilice la reflexión para invocar un método base anulado

¿Cómo se usa la llamada a la reflexión un método base que se reemplaza por clase 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 siempre muestra ‘Derivado’ …

No puedes hacer eso, incluso con reflexión. El polymorphism en C # en realidad garantiza que Derived.Foo() siempre se Derived.Foo() , incluso en una instancia de Cast Derived a su clase base.

La única manera de llamar a Base.Foo() desde una instancia Derived es hacerla explícitamente accesible desde la clase Derived :

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

Aunque la respuesta actual ya está aceptada, en realidad es posible sin tener que cambiar la clase original utilizando un 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 puedes ver, todavía es relativamente simple de hacer

Después de mucho tiempo, finalmente encuentro una solución mejor 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 solución usa la firma de constructor estándar de delegado:

 public Delegate(object target, IntPtr ftn) 

donde target es la instancia de destino y ftn es el puntero de función. Invocarlo directamente con el puntero de función del método base, por lo que el delegado apuntará al método base real, no al método reemplazado.

La reflexión le permite ver que el objeto d tiene un método “Foo” y también invocarlo.

Sin embargo, este método es un método virtual y es por eso que obtiene la implementación de ese método por una clase Derivada, ya que eso es lo que d (además de ser también convertible en una Base).

No hay una manera [directa] de invocar los métodos virtuales de la Base desde un objeto Derivado.
Como se muestra en Frederic Hamidi, el método de la clase Base puede ser expuesto por la clase Derivada (con un nombre diferente), pero eso no está realmente invocando el método de la Base, está invocando un método de la clase Derivada que llama a la Base método.

Aunque este enfoque de hacer que la clase derivada suministre un “proxy” al método de la clase base, finalmente hace lo que usted solicita, probablemente sea una mala idea hacer esto: es probable que haya un defecto en el diseño de su modelo de objetos: sería un caso de uso bastante extraño …

Lo que estás viendo es el comportamiento polimórfico que es por diseño. Cuando anula un método virtual, invocar ese método en la clase invalidada llama a la implementación de la clase descendant desde el VMT.

Cuál es su caso de uso, para ser honesto, esto huele un poco como un problema de diseño.

Quizás Kii estaba buscando algo como esto

 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) El casting no puede cambiar su tipo de clase.

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

2) Las anteriores son inválidas, porque nunca creaste ninguna instancia de objeto Base cuando creaste una instancia de Objeto Derived . Usted creó el objeto instancia de la Derived class que se heredó de la Base class . Espero, eso explica por qué no se podía invocar la función base con el objeto derivado