我是反射.emit 的新手,一直在尝试生成以下 c# 代码:
public class RepositoryWrapper
{
public void CallRepositoryMethod(IAddressRepository repository, Address address)
{
repository.NODE_I_NodeExtendedDetails_Address3(address.NodeId);
}
}
这是它的 il 表示:
IL_0000: nop
IL_0001: ldarg.1
IL_0002: ldarg.2
IL_0003: callvirt instance int32 ReflectionServices.Node::get_NodeId()
IL_0008: callvirt instance void ReflectionServices.IAddressRepository::NODE_I_NodeExtendedDetails_Address3(int32)
IL_000d: nop
IL_000e: ret
这是我用来创建它的代码:
internal static void Generate(this System.Reflection.Emit.ILGenerator @this, Type target,string method,Type instance)
{
var methodToCall = target.GetMethod(method);
var methodParams = methodToCall.GetParameters();
var instanceProperties = instance.GetProperties(BindingFlags.Public | BindingFlags.Instance);
var orderedProperties = (from mp in methodParams
join p in instanceProperties
on mp.Name.ToLower() equals p.Name.ToLower()
select p).ToArray();
//add properties to the string builder
//load the object reference onto the stack sothat we can access its methods
@this.Emit(OpCodes.Nop);
@this.Emit(OpCodes.Ldarg_1);
@this.Emit(OpCodes.Ldarg_2);
var property = orderedProperties.FirstOrDefault(x => x.Name == "NodeId");
if (property != null)
{
var getMethod = property.GetGetMethod();
@this.Emit(getMethod.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, getMethod);
}
//call method
@this.Emit(methodToCall.IsVirtual ? OpCodes.Callvirt : OpCodes.Call, methodToCall);
@this.Emit(OpCodes.Nop);
//return from function
@this.Emit(OpCodes.Ret);
}
这是我得到的错误:
System.InvalidProgramException: Common Language Runtime detected an invalid program.
Result StackTrace:
at ReflectionServices.Repository.NODE_I_NodeExtendedDetails3_Address40807399(Repository target, Address )
这是生成的 il:
nop
ldarg.1
ldarg.2
call instance int32 ReflectionServices.Node::get_NodeId()
callvirt instance void
ReflectionServices.Repository::
NODE_I_NodeExtendedDetails3_Address(int32)
nop
ret
任何人都可以看到我被卡住的问题是什么?
谢谢
这是我要求的dll和方法:
public sealed class ReflectionEmitWithDebuggingMethodGenerator
{
private AssemblyBuilder Assembly { get; set; }
private ModuleBuilder Module { get; set; }
private AssemblyName Name { get; set; }
public ReflectionEmitWithDebuggingMethodGenerator()
: base()
{
this.Name = new AssemblyName() { Name = Guid.NewGuid().ToString("N") };
this.Assembly = AppDomain.CurrentDomain.DefineDynamicAssembly(
this.Name, AssemblyBuilderAccess.RunAndSave,@"C:\Users\darren\Documents\Visual Studio 2012\Projects\UnityInjection");
this.AddDebuggingAttribute(this.Assembly);
this.Module = this.Assembly.DefineDynamicModule(this.Name.Name + ".dll", true);
}
public Action<TObject, TInstance> Generate<TObject, TInstance>(Type target, string methodN, Type instanceType)
{
var type = this.Module.DefineType(target.Namespace + "." + target.Name);
var methodName = methodN + target.GetHashCode().ToString();
var method = type.DefineMethod(methodName, MethodAttributes.Static | MethodAttributes.Public, typeof(void), new Type[] { target, instanceType });
method.DefineParameter(1, ParameterAttributes.In, "target");
method.DefineParameter(2, ParameterAttributes.In, "instance");
ILGenerator.Generate(method.GetILGenerator(), target,methodN,instanceType);
var createdType = type.CreateType();
var createdMethod = createdType.GetMethod(methodName);
return (Action<TObject, TInstance>)Delegate.CreateDelegate(typeof(Action<TObject, TInstance>), createdMethod);
}
}