加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – Reflection.emit System.InvalidProgramException:公共语

发布时间:2020-12-15 05:38:40 所属栏目:百科 来源:网络整理
导读:我是反射的新手.并且一直在尝试生成以下c#代码: public class RepositoryWrapper{ public void CallRepositoryMethod(IAddressRepository repository,Address address) { repository.NODE_I_NodeExtendedDetails_Address3(address.NodeId); }} 这是它的代表
我是反射的新手.并且一直在尝试生成以下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.

其次,当您返回此函数时,您将不得不包含一个目标对象,该对象是调用该方法的实例.为此,您可以使用Activator.CreateInstance调用默认生成的构造函数,并为您提供一个实例化对象以用作目标.用这些行替换Generate方法的最后一行来实现这一点.

var activatedObject = Activator.CreateInstance(type);

return (Action<TObject,TInstance>)Delegate.CreateDelegate(
    typeof(Action<TObject,activatedObject,createdMethod);

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读