Using reflection to override virtual method tables in C#
Asked Answered
H

4

4

Is there a way to change the virtual methods tables in C#? like change where a virtual method is pointing?

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
    }
}
Heterogenous answered 1/5, 2011 at 14:13 Comment(1)
You'd have to patch the object's method table. That cannot be done with managed code nor reflection.Sewage
S
4

Take a look at LinFu.

On Linfu's author's Blog there's an example of using LinFu.AOP to intercept and change calls even to methods of classes that you don't control directly.

Saintly answered 1/5, 2011 at 14:32 Comment(5)
Just for clarification, it is worth noting that LinFu.AOP does not use Reflection to accomplish this, rather it modifies the bytecode of compiled assemblies to insert hooks that it uses later. So it accomplishes what the OP wants to do, but not using the method which the OP was thinking about. I still think its a reasonable answer.Elbertina
this seems powerful, but how perfomant is it? btw salve paolo, non si vedono molti italiani qui :)Marvamarve
My understanding is that with LinFu's AOP you still use reflection when intercepting calls. @Marino: I've never tried to benchmark its performance against manually decorated classes. Linfu's author, @plaureano is on SO; it would be great if he chimed in directly.Saintly
LinFu uses a heavy amount of IL rewriting to do its interception, and it only uses reflection whenever it needs to pass information about the method that's currently being intercepted. For example, LinFu.AOP will rewrite your IL so that it passes the call to a generic IInterceptor interface, but it won't use reflection until it has to build the MethodInfo to pass to the interceptor. So to answer your question, 1) There is a slight performance penalty incurred by checking if the method should be intercepted and 2) reflection is only used to identify the method to be intercepted. HTHGrimsley
@Grimsley thanks for the clarification. I'm testing LinFu.AOP for a personal project and I'm impressed at how clean the code becomes. Very cool!Saintly
L
2

You cannot change the types with reflection, you can only reflect over the existing types.

You can, however, build new types using Reflection.Emit and related classes, but short of recompiling your assembly, a.B(); in your example will always call A.B().

Lemmon answered 1/5, 2011 at 14:30 Comment(0)
C
1

You can make virtual B call a default delegate you choose. The following will allow inheritance and overriding: (actually overriding of already overriden :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();
    }
}
}

Output:

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

You can even call base.B(); in cB.B() which will effectively call the overriden delegate but will give this output:

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

I suggest you to take some similar approach or a design pattern approach and do not even think of reflection Emit. You code will be unusable in high performance applications. Delegates are fast, reflection is SLOW.

Cythera answered 1/5, 2011 at 14:51 Comment(0)
H
1

Dani,

What's your ACTUAL problem? Paint me a picture of where-abouts "breaking" an existing, tested class definition "on the fly" would be desirable. Forgive my scepticism... but I have plenty of scripting experience, so I'll take code that doesn't generate itself as it's running any day. I even (sort of) hate IOC for just that reason.

However, If you want to create an overriding (or implementing) class-definitions "on the fly" then I suppose you'd use byte-code-generation (atleast that's what you'd do in Java)... Here's a forum thread on that topic: http://bellyphant.com/2006/11/csharp_bytecode_generation

You could also generate source-code, and compiling it on the fly. Here's a cute free little utils class to compile C# on the fly: http://www.agilekiwi.com/on_the_fly.htm

Good luck with it anyway... It's an interesting question.

Cheers. Keith.

Hendeca answered 1/5, 2011 at 15:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.