c# – Reflection.emit System.InvalidProgramException:公共语
我是反射的新手.并且一直在尝试生成以下c#代码:
public class RepositoryWrapper { public void CallRepositoryMethod(IAddressRepository repository,Address address) { repository.NODE_I_NodeExtendedDetails_Address3(address.NodeId); } } 这是它的代表: 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:UsersdarrenDocumentsVisual Studio 2012ProjectsUnityInjection"); 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,"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); } } 解决方法
比较编译输出和发射输出,只有一个区别:
编译: callvirt instance int32 ReflectionServices.Node::get_NodeId() 发出: call instance int32 ReflectionServices.Node::get_NodeId() 您调用int32 get_NodeId()的类型是ReflectionServices.Node,但是您要传递给要尝试复制的方法的对象的类型是Address.这使我相信必须虚拟调用ReflectionServices.Node上定义的属性访问器,可能是因为它继承自另一个类(或实现一个接口),该类在ReflectionServices.Node实现它之前声明该属性. 当您发出该行代码时,只需虚拟调用它: @this.Emit(OpCodes.Callvirt,getMethod); 编辑:根据进一步提供的代码,这是真正的解决方案. 因此,您在实现界面的基础知识方面存在问题: var method = type.DefineMethod(methodName,MethodAttributes.Static | Method... // ^^^^^^ 接口方法不是静态的;他们是实例成员.因此,首先需要在创建MethodBuilder时从attributes标志中删除MethodAttributes.Static. 其次,当您返回此函数时,您将不得不包含一个目标对象,该对象是调用该方法的实例.为此,您可以使用 var activatedObject = Activator.CreateInstance(type); return (Action<TObject,TInstance>)Delegate.CreateDelegate( typeof(Action<TObject,activatedObject,createdMethod); (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |