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

Mau*_*Mau 7 .net c#

我有以下情况:

在第三方库中(无法修改):

class A { public virtual void M() {} }

class B : A { public override void M() {} }
Run Code Online (Sandbox Code Playgroud)

在我自己的代码中:

class C : B { public override void M() {} }
Run Code Online (Sandbox Code Playgroud)

从我想要调用C的方法的实现(但不是!!).我可以吗?MAB

接受任何技巧,包括反思.我已经尝试过反射,但是使用MethodInfo我得到的反射typeof(A)仍然会产生一个虚拟调用(调用C后续堆栈溢出的实现).

派生CA是出了问题,由于重新实现的复杂性B.

des*_*sco 16

你可以生成动态方法来制作使用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);
Run Code Online (Sandbox Code Playgroud)

  • 这很聪明,但如果我看到在生产代码中使用它来解决建筑设计的局限性,那肯定会引起我的注意. (6认同)

Mer*_*ix2 2

很老的问题,但我最近遇到了类似的问题。德斯科的回答给出了关键的暗示。但生成的代理委托应该封装在类 C 中,可以是静态的并通过静态构造函数初始化,因此耗时的反射只需要一次。

// -- in foreign assembly
class A { public virtual void M() { Console.WriteLine("A.M"); }}
class B : A {public override void M() { Console.WriteLine("B.M"); }}
//
// -- in own assembly
class C : B
{
    private static Action<C> call_A_M;

    public override void M() {
        call_A_M(this);
        Console.WriteLine("C.M");
    }

    static C()
    {
        var m = typeof(A).GetMethod("M");
        var dm = new DynamicMethod("", 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);
        call_A_M = (Action<C>)dm.CreateDelegate(typeof(Action<C>));
    }
}
Run Code Online (Sandbox Code Playgroud)

但正如 Dan Bryant 已经提到的:永远不要在生产代码中使用这种肮脏的技巧。