通过Reflection.Emit生成代理仅在调试开始时起作用
||
大学的一项任务是使用Reflection.Emit实现一个简单的代理生成器/拦截器机制。
我想出了以下程序。
在Visual Studio中,在调试模式
[F5]
(调试->开始调试)下,它似乎可以正常工作,但是在不调试[Ctrl + F5]
(调试->未经调试开始)的情况下启动时,大多数时间会崩溃。
这两种模式有什么区别? (我不参考Debug <> Release模式)。
在多台计算机/设置(Win XP SP3 32位和64位,Windows 7 32位)上会发生此问题。
单击以粘贴。
// The proxy generator; I assume that the error is buried along the lines emitting the IL code
public static class ProxyGenerator
{
public static T Create<T>(object obj, IInterception interception)
{
Type type = obj.GetType();
TypeBuilder proxy = DefineProxy(type);
FieldBuilder wrappedField = DefinePrivateField(proxy, \"wrappedObject\", type);
FieldBuilder interceptionField = DefinePrivateField(proxy, \"interception\", interception.GetType());
DefineConstructor(proxy, wrappedField, interceptionField);
DefineInterfaceMethods(type, proxy, wrappedField, interceptionField);
return (T) Activator.CreateInstance(proxy.CreateType(), obj, interception);
}
private static TypeBuilder DefineProxy(Type type)
{
var assemblyName = new AssemblyName {Name = \"GeneratedProxyAssembly\"};
AssemblyBuilder assemblyBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(
assemblyName, AssemblyBuilderAccess.Run);
ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(\"GeneratedProxyModule\");
return moduleBuilder.DefineType(
type.Name + \"Proxy\",
type.Attributes,
typeof (object),
type.GetInterfaces());
}
private static FieldBuilder DefinePrivateField(TypeBuilder typeBuilder, string fieldName, Type fieldType)
{
return typeBuilder.DefineField(fieldName, fieldType, FieldAttributes.Private);
}
private static void DefineConstructor(TypeBuilder typeBuilder, params FieldBuilder[] parameters)
{
ConstructorBuilder ctor = typeBuilder.DefineConstructor(
MethodAttributes.Public, CallingConventions.Standard, parameters.Select(f => f.FieldType).ToArray());
// Emit constructor
ILGenerator g = ctor.GetILGenerator();
// Load \"this\" pointer and call base constructor
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Call, typeof(object).GetConstructor(new Type[0]));
// Store parameters in private fields
for (int i = 0; i < parameters.Length; i++)
{
// Load \"this\" pointer and parameter and store paramater in private field
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Ldarg, i + 1);
g.Emit(OpCodes.Stfld, parameters[i]);
}
// Return
g.Emit(OpCodes.Ret);
}
private static void DefineInterfaceMethods(Type type, TypeBuilder proxy, FieldInfo wrappedField, FieldInfo interceptionField)
{
// Loop through all interface methods
foreach (MethodInfo interfaceMethod in type.GetInterfaces().SelectMany(i => i.GetMethods()))
{
MethodInfo method = type.GetMethod(interfaceMethod.Name);
MethodBuilder methodBuilder = proxy.DefineMethod(
method.Name,
method.Attributes,
method.ReturnType,
method.GetParameters().Select(p => p.ParameterType).ToArray());
// Emit method
ILGenerator g = methodBuilder.GetILGenerator();
// Intercept before
EmitMethodCallOnMember(g, interceptionField, \"Before\", false);
// Delegate method call
EmitMethodCallOnMember(g, wrappedField, method.Name, true);
// Intercept after
EmitMethodCallOnMember(g, interceptionField, \"After\", false);
// Return
g.Emit(OpCodes.Ret);
}
}
private static void EmitMethodCallOnMember(ILGenerator g, FieldInfo field, string methodName, bool delegateParameters)
{
// Load \"this\" pointer to get address of field
g.Emit(OpCodes.Ldarg_0);
g.Emit(OpCodes.Ldflda, field);
MethodInfo method = field.FieldType.GetMethod(methodName);
if (delegateParameters)
{
// Load method parameters
for (int i = 0; i < method.GetParameters().Length; i++)
{
g.Emit(OpCodes.Ldarg, i + 1);
}
}
// Emit call
g.Emit(OpCodes.Call, method);
}
}
// Some infrastructure
public interface IInterception
{
void Before();
void After();
}
public class LogInterception : IInterception
{
public void Before()
{
Console.WriteLine(\"Before ... \");
}
public void After()
{
Console.WriteLine(\"... After\");
}
}
public interface ITest
{
string DoSomething(string s1, string s2);
}
public class Test : ITest
{
public string DoSomething(string s1, string s2)
{
Console.WriteLine(\"... doing something ...\");
return s1 + s2;
}
}
// The test program, expected output is down below
internal class Program
{
internal static void Main(string[] args)
{
var test = new Test();
var proxy = ProxyGenerator.Create<ITest>(test, new LogInterception());
Console.WriteLine(test.DoSomething(\"Hello\", \" World\"));
Console.WriteLine(\"----------------------------------------\");
Console.WriteLine(proxy.DoSomething(\"Hello\", \" World\"));
Console.ReadKey();
}
}
另一个问题:缩小此类问题的最佳方法是什么?
我试图将生成的程序集保存到磁盘,并在Reflector中打开生成的dll,但它似乎为空。
如上所述,以调试模式启动时,程序似乎可以运行并输出以下输出。
... doing something ...
Hello World
----------------------------------------
Before ...
... doing something ...
... After
Hello World
谢谢你的时间。
没有找到相关结果
已邀请:
1 个回复
揽芳僵迷仇
或
模式下运行程序时,我才出现致命异常。 啊,我知道了。将
替换为
。即使没有调试器,它也能正常工作(我只是运行.exe)。
用于使用
或
关键字作为参数传递给方法的字段。