Frage

Sie sich den folgenden trivialen Code:

using System;   
class Test
{
    delegate int FooDelegate(int i);
    FooDelegate Foo = FooImplementation;
    static int FooImplementation(int i)
    {
        return i + 1;
    }

    public static void Main()
    {
         Foo(1);
    }
}

Was würde Ich mag es, inject einige Debug-Code in den Foo Delegierten tun, was äquivalent wäre:

FooDelegate Foo = delegate(int i)
{
    try
    {
        DebugPrologue();
        return FooImplementation(i);
    }
    finally
    {
        DebugEpilogue();
    }
};

Die Wendung ist, dass ich in der Lage sein muss, dies zu tun in Laufzeit , so Kompilierung-und Post-Processing-Methoden sind indiskutabel.

Mein erster Ansatz verwendet Delegate.Combine () den Prolog und Epilog Methoden zum Foo Delegaten hinzuzufügen. Ach, das wird nicht funktionieren, da es munges Werte zurück.

Meine aktuelle Idee ist System.Reflection.Emit und Dynamic als mögliche Lösung zu verwenden. Soweit ich sagen kann, ich brauche die Method für FooImplementation zu bekommen, bekommt seine Method, konvertiert, die zu einer Dynamic und inject meiner Anprobe schließlich in diesen Block.

Leider habe ich absolut keine Ahnung, wie dies zu tun. Wer bereit, eine Hand zu verleihen? Oder haben Sie eine andere (vorzugsweise einfacher) Idee?

Edit: die Use-Case ist hier Debuggen einer OpenGL-Bindung (http://www.opentk.com). Wir haben zu injizieren 2226 Methoden mit extrem unterschiedlichen Parametern, so ein allgemeiner Ansatz notwendig ist.

War es hilfreich?

Lösung 6

Was ich schließlich war am Ende dabei meine eigene Umschreiben Lösung mit Mono.Cecil zu implementieren. Einfach, schnell und es funktioniert gut. Leider hat dies als Post-Build-Ereignis durchgeführt werden, so dass dies nicht wirklich Runtime Code-Injektion ist.

Andere Tipps

Sie können Ausdrücke verwenden.

var param = Expression.Parameter(typeof(int), "i");

Foo = Expression.Lambda(
         Expression.TryFinally(
            Expression.Block(
               <expression for DebugPrologue>,
               Expression.Invoke(<expression for FooImplementation>, param)),
            <expression for DebugEpilogue>),
         param)
      .Compile();

Auf diese Weise können Sie die Ausdrücke für den Prolog und Epilog im laufenden Betrieb aufzubauen.

Beachten Sie sicher, was Sie versuchen, zu tun, aber wenn es einfach ist die FooImplementation Umleitung, die an der Foo zeigte Feld dann können Sie einfach tun:

class Test
{
    delegate int FooDelegate(int i);
    static FooDelegate Foo = FooImplementation;

    static int FooImplementation(int i)
    {
        return i + 1;
    }

    public static void Main()
    {
        Inject();
        Foo(1);
    }


    public static void Inject()
    {
        var oldImpl = Foo;

        Foo = i =>
            {
                try
                {
                    BeginDebug();
                    return oldImpl(i);
                }
                finally
                {
                    EndDebug();
                }
            };
    }

    public static void BeginDebug()
    {
        Console.WriteLine("Begin Foo");
    }

    public static void EndDebug()
    {
        Console.WriteLine("End Foo");
    }
}

Natürlich ist die Inject muss nicht in der gleichen Klasse sein, aber wenn das Feld / Eigenschaft nicht öffentlich zugänglich ist, Sie zu verwenden Reflexion, es zu tun haben werden, noch nicht so schwer, aber.

Haben Sie wie mit so etwas in Betracht gezogen: Postsharp? http://www.sharpcrafters.com/postsharp

oder Politik Injection Enterprise Library? http://msdn.microsoft.com/en-us/library/ff650672.aspx

oder sogar Mono.Cecil? http://www.mono-project.com/Cecil

TypeMock auch vielleicht eine tragfähige Lösung für Ihr Problem: http://www.typemock.com/

Sie können auch die Realproxy-Klasse verwenden könnten (http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realproxy.aspx) Ihre eigene Proxy zur Laufzeit zu erzeugen, wird zunächst Anruf Ihre injizierte Code und dann die eigentliche Methode aufrufen.

Sie können auch versuchen, CInject auf Codeplex einzuspritzen Code in verwaltetem Code (C # oder VB.NET) mit große Leichtigkeit.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top