Использование отражения для переопределения таблиц виртуальных методов в C#

Есть ли способ изменить таблицы виртуальных методов в 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 ответа

Посмотрите на LinFu.

В блоге автора Linfu есть пример использования LinFu.AOP для перехвата и изменения вызовов даже для методов классов, которые вы не контролируете напрямую.

Вы не можете изменять типы с помощью отражения, вы можете только отражать существующие типы.

Тем не менее, вы можете создавать новые типы, используя Reflection.Emit и связанные классы, но без перекомпиляции вашей сборки, a.B(); в вашем примере всегда будет звонить A.B(),

Дани,

Какая у вас ФАКТИЧЕСКАЯ проблема? Нарисуйте мне картину того, где-бы "сломать" существующее, проверенное определение класса "на лету" было бы желательно. Простите за мой скептицизм... но у меня достаточно опыта написания сценариев, поэтому я возьму код, который не генерирует себя, так как работает в любой день. Я даже (вроде) ненавижу МОК именно по этой причине.

Однако, если вы хотите создать переопределение (или реализацию) определений классов "на лету", то я полагаю, что вы будете использовать генерацию байт-кода (по крайней мере, это то, что вы будете делать в Java)... Вот форум тема на эту тему: http://bellyphant.com/2006/11/csharp_bytecode_generation

Вы также можете генерировать исходный код и компилировать его на лету. Вот милый классный бесплатный утилитный класс для компиляции C# на лету: http://www.agilekiwi.com/on_the_fly.htm

В любом случае, удачи... Это интересный вопрос.

Приветствия. Кит.

Вы можете сделать виртуальный вызов 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. Ваш код будет непригодным для высокопроизводительных приложений. Делегаты быстрые, отражение МЕДЛЕННОЕ.

Другие вопросы по тегам