Use reflection to invoke an overridden base method

2019-01-04 13:50发布

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'...

8条回答
聊天终结者
3楼-- · 2019-01-04 13:59

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

查看更多
孤傲高冷的网名
4楼-- · 2019-01-04 14:02

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...

查看更多
一纸荒年 Trace。
5楼-- · 2019-01-04 14:05
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

查看更多
ら.Afraid
6楼-- · 2019-01-04 14:07

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.

查看更多
别忘想泡老子
7楼-- · 2019-01-04 14:08

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.

查看更多
登录 后发表回答