23

How to use reflection call a base method that is overridden by derived class?

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();
}

This code always shows 'Derived'...

Timwi
  • 65,159
  • 33
  • 165
  • 230
Kii
  • 772
  • 1
  • 8
  • 16
  • I created an extension from @Doggett's answer below that would allow you to do this `typeof(Base).GetMethod("Foo").InvokeNotOverride(d, null);`. You can find it here: http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection.html – Luis Perez Aug 13 '12 at 19:18
  • @LuisPerez Link is broken, but http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection/ works. – jnm2 Sep 10 '20 at 22:05

9 Answers9

40

After a long time, I finally find a better solution than 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<string>)Activator.CreateInstance(typeof(Func<string>), obj, ftn);
        Console.WriteLine(func());
    }
}

class Override
{
    public override string ToString()
    {
        return "Nope";
    }
}

This solution use the standard constructor signature of delegate:

public Delegate(object target, IntPtr ftn)

where target is the target instance and ftn is the function pointer. It directly invoke it with the function pointer of base method, so the delegate will point to the actual base method, not the overridden method.

Kii
  • 772
  • 1
  • 8
  • 16
37

Even though the current answer is already accepted, it's actually possible without having to change the original class by using a dynamic method like this:

    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<Derived>)dm.CreateDelegate(typeof(Action<Derived>));
        BaseFoo(foo);

        Console.ReadKey();
    }

as you can see it's still relatively simple to do

Doggett
  • 3,364
  • 21
  • 17
  • 4
    Worked perfectly thanks. I created an extension from it that allows me to do this `typeof(Base).GetMethod("Foo").InvokeNotOverride(d, null);`. You can find it here: http://www.simplygoodcode.com/2012/08/invoke-base-method-using-reflection.html – Luis Perez Aug 13 '12 at 19:15
  • 1
    This works because it is exactly how the C# compiler creates the calls to the base class in the first place, although I had hoped it wasn't the only way to do it.... – Orvid King Jan 04 '13 at 23:01
  • 1
    Shouldn't that be `Ldarg_0`? Argument 0 is `this` within instance methods. – Zenexer Sep 10 '13 at 11:41
  • @Zenexer It's `Ldarg_1` because this creates an instance method, so there's a (possibly null, it doesn't matter) *this* for the call as argument 0, then *foo* is argument 1, which becomes the *this* argument (argument 0) when the call is being done. If the `DynamicMethod` was created with `MethodAttributes.Static`, then there'd be no *this* on the call to the delegate, and it should indeed be `Ldarg_0`). – Jon Hanna Jan 04 '14 at 15:29
3

This can be achieved through Code emit

http://blogs.msdn.com/b/rmbyers/archive/2008/08/16/invoking-a-virtual-method-non-virtually.aspx

jpfx1342
  • 868
  • 8
  • 14
2

You can't do that, even with reflection. Polymorphism in C# actually guarantees that Derived.Foo() will always be called, even on an instance of Derived cast back to its base class.

The only way to call Base.Foo() from a Derived instance is to explicitly make it accessible from the Derived class:

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

    public void BaseFoo()
    {
        base.Foo();
    }
}
Frédéric Hamidi
  • 258,201
  • 41
  • 486
  • 479
1

Here is a general form of @Kii answer above:

// returns a delegate (of type methodType) that calls obj.base.method(..)
static object VirtualMethodBase(Type methodType, string methodName, Object obj) {
  var method = obj.GetType().BaseType.GetMethod(methodName);
  var ftn = method.MethodHandle.GetFunctionPointer();
  return Activator.CreateInstance(methodType, obj, ftn);
}

usage:

public class Base {
  public override string ToString() => "Base";
  public virtual int F(int x, int y) => x+y; 
}

public class Derived : Base {
  public override string ToString() => "Derived";
  public override int F(int x, int y) => x*y; 
}

var b = new Base();
var d = new Derived();

var sb = b.ToString(); // "Base"
var fb = b.F(2, 3); // 5

var sd = d.ToString(); // "Derived"
var fd = d.F(2, 3); // 6

// obj.base.ToString()
static string ToStringBase(object obj) => ((Func<string>)VirtualMethodBase(typeof(Func<string>), "ToString", obj))();

// obj.base.F(x, y)
static int FBase(Base bobj, int x, int y) => ((Func<int, int, int>)VirtualMethodBase(typeof(Func<int, int, int>), "F", bobj))(x, y);

var sd1 = ToStringBase(d); // "Base"
var fd1 = FBase(d, 2, 3); // 5
kofifus
  • 17,260
  • 17
  • 99
  • 173
0

Reflection allows you to see that the object d has a "Foo" method and also to invoke it.

This method however is a virtual method and that's why you're getting the implementation of that method by a Derived class since that is what d is (in addition to also being castable to a Base).

There is no [direct] way to invoke the Base's virtual methods from a Derived object.
As shown in in Frederic Hamidi's, the Base class' method can be exposed by the Derived class (under a different name), but that's not really invoking the Base's method, it is invoking a method of the Derived class which happens to call the Base's method.

Although this approach of having the Derived class supply a "proxy" to the method of the Base class, ultimately does what you ask for, it is probably a bad idea to do this: there's likely a flaw in the design of your object model: it would be a rather odd use case...

mjv
  • 73,152
  • 14
  • 113
  • 156
0

What you are seeing is the polymorphic behaviour that is by design. When you override a virtual method, invoking that method on the overridden class calls the decendant class's implementation from the VMT.

What is your use case, to be honest this smells a little like a design problem.

Tim Jarvis
  • 18,465
  • 9
  • 55
  • 92
-2

Maybe Kii was looking for something like this

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();
}
zajonc
  • 1,935
  • 5
  • 20
  • 25
Hasaan
  • 1
  • 1
  • 1
-2
Base b = (Base)d;
Console.WriteLine(b.GetType());  //output:Derived

1)Casting cannot change it's class type.

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

2) Above are invalid, because you never created any Base object instance when you created Derived object instance. You created instance object of Derived class which inherited from Base class. Hope, that explains why you could not invoke base function with derived object

chrizyuen
  • 32
  • 3
  • -1: IMHO, what you wrote is irrelevant, missing the point and far inferior to all the earlier posts. Moreover, your explanation of "return base" compiler error is simply wrong: a)you do not have to create anything to be able to return it, b)an instance of object of class "Derived" actually IS an instance of class "Base" - so simple return 'this' would be acceptable there, c) it is a just a syntax error: keyword BASE cannot be used like a 'this' - it is kind of a call context specifier, not kind of a special variable like 'this' keyword. – quetzalcoatl Apr 11 '12 at 12:44
  • The point you cannot "return base" is that in C#, contrary to C++, there is NO such thing as OBJECT SLICING. Had the syntax "return base" been allowed, it would have to behave differently than "return this" and it would have to SLICE the current instance down to the base definition and return some kind of copy, or a wrapper that would redirect method calls. There are no such mechanisms. Moreover, there are no such mechanisms in C++ either: the object slicing that is found there is a side effect of default copy constructors and implicit type conversions. – quetzalcoatl Apr 11 '12 at 12:50