gpt4 book ai didi

visual-studio-2010 - 通过 Reflection.Emit 生成代理仅在开始调试时有效

转载 作者:行者123 更新时间:2023-12-05 00:38:14 24 4
gpt4 key购买 nike

大学的一项任务是使用 Reflection.Emit 实现一个简单的代理生成器/拦截器机制。
我想出了以下程序。

它似乎在 Debug模式下的 Visual Studio 中工作得很好[F5] (Debug -> Start Debugging) 但大部分时间在没有调试的情况下启动时崩溃 [Ctrl + F5] (调试 -> 开始而不调试)。

这两种模式有什么区别? (我 指的是调试 <> Release模式)。
该问题发生在多台机器/设置(Win XP SP3 32 位和 64 位,Windows 7 32 位)上。

Click用于粘贴。

// 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,但它似乎是空的。

如上所述,在 Debug模式下启动时,程序似乎可以工作并打印以下输出。
... doing something ...
Hello World
----------------------------------------
Before ...
... doing something ...
... After
Hello World

谢谢你的时间。

最佳答案

尝试明确设置 x86项目设置选项卡上的模式。

只有在 x64 中运行程序时才会出现致命异常或 AnyCpu模式。

啊,我知道了。替换 LdfldaLdfld .即使没有调试器,它也能正常工作(我只是运行了 .exe)。Ldflda用于您作为参数传递给方法的字段 refout关键词。

关于visual-studio-2010 - 通过 Reflection.Emit 生成代理仅在开始调试时有效,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/5889428/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com