c# - InvalidProgramException 尝试通过 Reflection.Emit 调用静态方法

标签 c# .net-3.5 reflection.emit

我正在尝试创建一个动态类型,它基本上将一些方法包装在静态类上。我创建了一个名为 Wrap 的静态方法,它有一个通用参数(应该是一个接口(interface))和一个普通参数(具有静态方法的类的类型)。

例如

IInterfaceTest obj = StaticInterface.Wrap<IInterfaceTest>(typeof(StaticClassNameHere));
obj.TestInterfaceMethod();

但是我生成的代码显然在某个地方被破坏了,因为当我调用该方法时收到 InvalidProgramException 。

我的代码基于我制作的测试类的 ILDasm 输出,据我所知,我输出了相同的代码。但它不起作用...

public static class StaticInterface
{
    private static AssemblyBuilder _asm = null;
    private static ModuleBuilder _mod = null;
    private static Type _thisType = typeof(StaticInterface);
    private static int _count = 0;
    public static T Wrap<T>(Type type)
    {
      ILGenerator ilgen;

      if (_asm == null)
      {
         _asm = AppDomain.CurrentDomain.DefineDynamicAssembly(new System.Reflection.AssemblyName(_thisType.Name), AssemblyBuilderAccess.Run);
         _mod = _asm.DefineDynamicModule(_thisType.Name);
      }

      string newTypeName = _thisType.Name + "._" + _count++;

      TypeBuilder typBuilder = _mod.DefineType(newTypeName, System.Reflection.TypeAttributes.Class | System.Reflection.TypeAttributes.Public);
      typBuilder.AddInterfaceImplementation(typeof(T));

      ConstructorBuilder conBuilder = typBuilder.DefineDefaultConstructor(System.Reflection.MethodAttributes.Public);

      foreach (MethodInfo method in typeof(T).GetMethods())
      {
         ParameterInfo[] parameters = method.GetParameters();
         Type[] paramTypes = new Type[parameters.Length];

         for (int j = 0; j < parameters.Length; j++)
         {
            paramTypes[j] = parameters[j].ParameterType;
         }

         MethodBuilder mth = typBuilder.DefineMethod(method.Name,
            MethodAttributes.Public | MethodAttributes.Virtual | MethodAttributes.HideBySig | MethodAttributes.NewSlot | MethodAttributes.Final,
                        method.ReturnType,
                        paramTypes);

          ilgen = mth.GetILGenerator();
          ilgen.Emit(OpCodes.Nop);

          for (short j = 0; j < parameters.Length; j++)
          {
             ilgen.Emit(OpCodes.Ldarg, j + 1);
          }

          MethodInfo callMeth = type.GetMethod(method.Name, BindingFlags.Public | BindingFlags.Static, null, paramTypes, null);

          ilgen.EmitCall(OpCodes.Call, callMeth, null);

          if (method.ReturnType != null && method.ReturnType != typeof(void))
          {
             ilgen.Emit(OpCodes.Stloc_0);
             Label end = ilgen.DefineLabel();
             ilgen.Emit(OpCodes.Br_S, end);

             ilgen.MarkLabel(end);
             ilgen.Emit(OpCodes.Ldloc_0);
          }

          ilgen.Emit(OpCodes.Ret);
       }

       typBuilder.CreateType();

       return (T)_asm.CreateInstance(newTypeName, false, BindingFlags.Public | BindingFlags.Instance, null, null, null, null);
    }
}

最佳答案

主要是,我认为这与您对返回类型的处理有关:

ilgen.EmitCall(OpCodes.Call, callMeth, null);
if (method.ReturnType != null && method.ReturnType != typeof(void))
{
    ilgen.Emit(OpCodes.Stloc_0);
    Label end = ilgen.DefineLabel();
    ilgen.Emit(OpCodes.Br_S, end);

    ilgen.MarkLabel(end);
    ilgen.Emit(OpCodes.Ldloc_0);
}
ilgen.Emit(OpCodes.Ret);
  • 您尚未定义任何局部变量,因此 STLoc_0Ldloc_0 是非法的
  • 分支只是...分支到下一行(所以什么也不做),所以这基本上是“存储到 X,从 X 加载”,如果我们不关心侧面,那么这是一个无操作 -分配 X 的效果
  • 这完全没有必要无论如何 - 只需将返回值留在堆栈上,因为它需要匹配(意思是:如果该方法不返回值,那么没关系;如果它 < em>确实返回一个值,那么该值已经是堆栈上的值 - 即正是我们想要的)

所以更简单(并且有效)的实现就是:

ilgen.EmitCall(OpCodes.Call, callMeth, null);
ilgen.Emit(OpCodes.Ret);

关于c# - InvalidProgramException 尝试通过 Reflection.Emit 调用静态方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12195611/

相关文章:

c# - 好奇心 : Why does Expression<. ..> 编译时运行速度比最小 DynamicMethod 快?

c# - 如何将信息存储在 .Net 中的可执行文件中

c# - LINQ to Entities 基于字符串的动态 Where

c# - C#的音频播放和频谱分析库

.net-3.5 - RSACryptoServiceProvider.ImportParameters 抛出 System.Security.Cryptography.CryptographicException : Bad Data

c# - 加载程序集并使用不同的名称和扩展名复制它

c# - 如何用 where 指定泛型?

wpf - 能够检测这是否是用户首次登录 Windows 7

web-services - 使用 jQuery 从 .NET 服务获取 JSON 数据 : confused with ajax setup

c# - 如何使用 IL Emit 定义相互引用的两种类型