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