使用DynamicMethod注入运行时代码?
-
08-10-2019 - |
题
考虑以下微不足道的代码:
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
Typemock也可能是您问题的可行解决方案:http://www.typemock.com/
您还可以使用RealProxy类(http://msdn.microsoft.com/en-us/library/system.runtime.remoting.proxies.realproxy.aspx)在运行时生成自己的代理,该代码将首次调用您的代码然后调用实际方法。
您也可以尝试 cin 在CodePlex上,可以轻松地将代码注入托管代码(C#或VB.NET)。