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