4

有没有办法更改 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

4 回答 4

4

看看林福

在Linfu的作者的博客上,有一个使用 LinFu.AOP 来拦截和更改对您不直接控制的类的方法的调用的示例。

于 2011-05-01T14:32:46.420 回答
2

你不能用反射改变类型,你只能反射现有的类型。

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

于 2011-05-01T14:30:42.837 回答
1

丹妮,

你的实际问题是什么?给我画一张“动态”“打破”现有的、经过测试的类定义的图片。请原谅我的怀疑……但我有丰富的脚本编写经验,所以我将采用不会在任何一天运行时自行生成的代码。出于这个原因,我什至(有点)讨厌国际奥委会。

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

您还可以生成源代码并即时编译它。这是一个可爱的免费小工具类,可以即时编译 C#:http ://www.agilekiwi.com/on_the_fly.htm

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

干杯。基思。

于 2011-05-01T15:08:37.517 回答
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

您甚至可以调用base.B();cB.B() ,这将有效地调用覆盖的委托,但会给出以下输出:

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

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

于 2011-05-01T14:51:53.690 回答