使用反射覆盖C#中的虚方法表

时间:2011-05-01 14:13:32

标签: c# .net clr vtable virtual-method

有没有办法在C#中更改虚方法表?比如改变虚拟方法指向的位置?

class A
{
    public virtual void B()
    {
        Console.WriteLine("B");
    }
}
class Program
{
    public static void MyB(A a)
    {
        Console.WriteLine("MyB");
    }
    public static void Main(string[] Args)
    {
        A a = new A();
        // Do some reflection voodoo to change the virtual methods table here to make B point to MyB
        a.B(); // Will print MyB
    }
}

4 个答案:

答案 0 :(得分:4)

看看LinFu

Linfu's author's Blog上有一个使用LinFu.AOP拦截和更改调用的例子,甚至是你不直接控制的类的方法。

答案 1 :(得分:2)

您不能使用反射更改类型,只能反映现有类型。

但是,您可以使用Reflection.Emit和相关类构建新类型,但是如果不重新编译程序集,示例中的a.B();将始终调用A.B()

答案 2 :(得分:1)

您可以将虚拟B调用设为您选择的默认代理。 以下将允许继承和覆盖:(实际覆盖已经覆盖:D)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Runtime.InteropServices;

namespace ConsoleApplication1
{
    class A
{
    public delegate void delegateB();
    public delegateB _B;

    public A() {
      _B = B;
    }
    public void Override(delegateB newB)
    {
        _B = newB;
    }

    public virtual void B()
    {
        if (_B != null && _B != this.B) {
            Console.WriteLine("OVERRIDEN B IN A");
            _B();
        }
        else {
        Console.WriteLine("VIRTUAL B IN A");
        }
    }
}

    class cB : A {
        public override void B() {
            if (base._B != null && base._B != this.B)
            {
                Console.WriteLine("OVERRIDEN B IN B");
                _B();
            }
            else
            {
                Console.WriteLine("IN B");
            }

        }
    }

class Program
{
    class Overrider {
       public void MyB()
       {
           Console.WriteLine("MyB");
       }
    }

    public static void Main(string[] Args)
    {
        A a = new A();
        a.B();
        Overrider ovr = new Overrider();
        a.Override(ovr.MyB);
        a.B(); // Will print MyB
        cB b = new cB();
        b.B();
        b.Override(ovr.MyB);
        b.B();
    }
}
}

输出:

VIRTUAL B IN A
OVERRIDEN B IN A
MyB
IN B
OVERRIDEN B IN B
MyB

你甚至可以在cB.B()中调用base.B();,这将有效地调用overriden委托,但会给出这个输出:

VIRTUAL B IN A
OVERRIDEN B IN A
MyB
IN B
OVERRIDEN B IN B
OVERRIDEN B IN A
MyB

我建议你采取一些类似的方法或设计模式的方法,甚至不要想到反射Emit。您的代码在高性能应用程序中将无法使用。代表们很快,反思很慢。

答案 3 :(得分:1)

达尼,

你的实际问题是什么?给我画一张“在运行中”“破坏”现有的,经过测试的类定义的图片是可取的。请原谅我的怀疑......但我有很多脚本经验,所以我会把代码运行起来,因为它在任何一天都在运行。我甚至(有点)讨厌IOC。

但是,如果你想“动态”创建一个重写(或实现)类定义,那么我想你会使用字节码生成(至少你在Java中做的那样)......这是关于该主题的论坛帖子:http://bellyphant.com/2006/11/csharp_bytecode_generation

您还可以生成源代码,并在运行时对其进行编译。这是一个可爱的免费小工具类,可以动态编译C#:http://www.agilekiwi.com/on_the_fly.htm

无论如何,祝你好运......这是一个有趣的问题。

干杯。基思。