使用reflection来调用重写的基本方法
如何使用reflection调用被派生类重写的基本方法?
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(); }
此代码始终显示“派生”…
你不能这样做,即使是用reflection。 C#中的多态性实际上保证Derived.Foo()
将始终被调用,即使在Derived
的实例上也会被调用回其基类。
从Derived
实例调用Base.Foo()
的唯一方法是显式地使它可以从Derived
类访问:
class Derived : Base { public override void Foo() { Console.WriteLine("Derived"); } public void BaseFoo() { base.Foo(); } }
即使当前的答案已经被接受,但实际上可以通过使用这样的动态方法来更改原始类:
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(); }
你可以看到它仍然相对简单
经过很长一段时间,我终于找到了比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"; } }
此解决方案使用委托的标准构造函数签名:
public Delegate(object target, IntPtr ftn)
其中target是目标实例,ftn是函数指针。 它使用base方法的函数指针直接调用它,因此委托将指向实际的基本方法,而不是重写的方法。
这可以通过代码发出来实现
http://blogs.msdn.com/b/rmbyers/archive/2008/08/16/invoking-a-virtual-method-non-virtually.aspx
reflection允许您查看对象d具有“Foo”方法并且还可以调用它。
然而,这个方法是一个虚方法 ,这就是你通过Derived类获得该方法的实现的原因,因为这就是d(除了也可以转换为Base)。
没有[直接]方法从Derived对象调用Base的虚方法。
如Frederic Hamidi所示,Base类的方法可以通过Derived类(在不同的名称下)公开,但是它并没有真正调用Base的方法,它正在调用Derived类的方法,该方法恰好调用Base的方法。
虽然这种方法让Derived类为Base类的方法提供了“代理”,但最终会按照你的要求执行,但这样做可能是个坏主意:对象模型的设计可能存在缺陷:这将是一个相当奇怪的用例……
您所看到的是设计中的多态行为。 覆盖虚方法时,在重写的类上调用该方法将从VMT调用后代类的实现。
你的用例是什么,说实话,这有点像设计问题。
也许Kii正在寻找这样的东西
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)施法不能改变它的类类型。
class Derived : Base { public override void Foo() { Console.WriteLine("Derived"); } public Base getBase() { return base; //compiler invalid } }
2)上面的内容无效,因为您在创建Derived
对象实例时从未创建过任何Base
对象实例。 您创建了从Base class
inheritance的Derived class
实例对象。 希望,这解释了为什么你不能用派生对象调用基函数