代码之家  ›  专栏  ›  技术社区  ›  Mau

如何(非虚拟地)调用虚拟方法的原始实现?

  •  7
  • Mau  · 技术社区  · 14 年前

    在第三方库中(不能修改):

    class A { public virtual void M() {} }
    
    class B : A { public override void M() {} }
    

    class C : B { public override void M() {} }
    

    C M 我想打电话 A 的(但不是 B 是的!!)。我可以吗?

    MethodInfo 我从中得到的 typeof(A) 仍然生成虚拟呼叫(呼叫 的实现,随后堆栈溢出)。

    派生 C级 B类 .

    4 回复  |  直到 14 年前
        1
  •  17
  •   desco    14 年前

    您可以生成动态方法,使代理使用Call(而不是CallVirt)指令

            var x = new C();
            var m = typeof (A).GetMethod("M");
            var dm = new DynamicMethod("proxy",  typeof (void), new [] {typeof(C)}, typeof (C));
            var il = dm.GetILGenerator();
            il.Emit(OpCodes.Ldarg_0);
            il.Emit(OpCodes.Call, m);
            il.Emit(OpCodes.Ret);
            var action = (Action<C>)dm.CreateDelegate(typeof (Action<C>));
            action(x);
    
        2
  •  2
  •   Timwi    14 年前

    当然,这样做的不幸后果是,您可能需要重新实现B中的部分或全部功能。如果需要,您可以从Reflector复制代码。我意识到这听起来不可取,但我仍然认为最好使用不可修改的代码,因为它有一个已知的问题,导致您的问题。

        3
  •  1
  •   Timwi    14 年前

    恐怕这是不可能的,因为您描述虚拟方法的目的是为了使重写透明。所以唯一的办法就是通过变通办法。

    让我试着想出一个,但请注意,这是一个黑客的建议。如果您的代码中真的需要这个构造,它可能表示您的代码在其他地方有一个基本的设计缺陷,因此重构某些东西可能比用另一个设计缺陷填充它更可取。但不管怎样。。。

    class A {
        public virtual void M() { m_protected(); }
        protected void m_protected() { /* code goes here */ }
    }
    
    class B {
        public override void M() { /* code here, possibly invoking base.M() */ }
    }
    
    class C {
        public override void M() { m_protected(); }
    }
    
        4
  •  0
  •   zvone    14 年前

    可能

    class A {
        protected virtual void basicM() {}
        public virtual void M() { basicM(); }
    }
    class C {
        public override void M() { basicM(); }
    }
    

    顺便说一句,如果您像我在示例中那样命名方法,那么您可能应该重新考虑整个过程。如果这个层次结构是合理的,那么 basicM 可能会执行一些应该是具有不同名称的独立方法的操作,甚至可能是公共方法。