考虑以下微不足道的代码:

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);
    }
}

我想做的就是将一些调试代码注入FOO代表,这是等效的:

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

扭曲是我必须能够在 运行, ,因此编译时间和后处理方法不可能解决。

我的最初方法使用delegate.combine()将序言和结语方法添加到FOO代表中。 las,这是不起作用的,因为它返回值。

我目前的想法是使用System.Reflection.emit和DynamicMethod作为潜在解决方案。据我所知,我需要获取MethodInfo进行fooimplentation,获取其方法机体,将其转换为动态方法,然后将我的尝试封锁注入其中。

不幸的是,我绝对不知道该怎么做。有人愿意伸出援手吗?还是您有另一个(最好简单)的想法?

编辑:这里的用例是调试OpenGL绑定(http://www.opentk.com)。我们必须注入2226种具有截然不同的参数的方法,因此必须采用一般方法。

有帮助吗?

解决方案 6

我终于做的是使用Mono.Cecil实施自己的重写解决方案。简单,快速,效果很好。不幸的是,这必须作为后构建事件进行,因此实际上不是运行时代码注入。

其他提示

您可以使用表达式。

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();

这样,您可以在运行时构建序言和结语的表达式。

请确保您要做什么,但是如果只是重定向 FooImplementation 那指着 Foo 字段然后您可以简单地做:

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");
    }
}

当然,注入不必参加同一班级,但是,如果该字段/属性不公开访问,则必须使用反射来执行此功能,但仍然并不难。

您是否考虑过以下内容:PostSharp?http://www.sharpcrafters.com/postsharp

还是企业图书馆政策注入?http://msdn.microsoft.com/en-us/library/ff650672.aspx

甚至是单声道?http://www.mono-project.com/cecil

Typemock也可能是您问题的可行解决方案:http://www.typemock.com/

您还可以使用RealProxy类(http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realproxy.aspx)在运行时生成自己的代理,该代码将首次调用您的代码然后调用实际方法。

您也可以尝试 cin 在CodePlex上,可以轻松地将代码注入托管代码(C#或VB.NET)。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top