IL 使用 Reflection.Emit 调用带有 params object[] 参数的方法

2024-03-28

我正在编写一个需要稍后类型构建的库。库使用平台.Net core 2.0

我使用 Reflection.Emit 生成的某些类型存在问题

public class GeneratedA : A, IA
{
    public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs)
    {
        DoClass(arg0, arg1, arg2, arg3, arg4, otherArgs);
    }
}

对于这些类型:

public interface IA
{
    void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4,  params object[] otherArgs);
}
public class A
{
    public void DoClass(params object[] args)
    {
    }
}

示例 IL 代码:

class Program
{
    public static class Generator
    {
        public static T Create<T>()
            where T : class
        {
            AssemblyName aName = new AssemblyName("DynamicAssembly");
            AssemblyBuilder ab = AssemblyBuilder.DefineDynamicAssembly(new AssemblyName(Guid.NewGuid().ToString()), AssemblyBuilderAccess.Run);
            ModuleBuilder mb = ab.DefineDynamicModule(aName.Name);

            var interfaceType = typeof(T);
            var interfaceMethod = interfaceType.GetMethod("DoInterface");
            var interfaceMethodArgs = interfaceMethod.GetParameters().Select(x => x.ParameterType).ToArray();
            var classType = typeof(A);
            var classMethod = classType.GetMethod("DoClass");
            var returnType = typeof(void);
            var baseType = typeof(object);
            var baseConstructor = baseType.GetConstructor(BindingFlags.Public | BindingFlags.FlattenHierarchy | BindingFlags.Instance, null, Type.EmptyTypes, null);


            TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, baseType);


            ConstructorBuilder ctor = tb.DefineConstructor(MethodAttributes.Public, CallingConventions.Standard, Type.EmptyTypes);
            ILGenerator ctorIL = ctor.GetILGenerator();
            ctorIL.Emit(OpCodes.Ldarg_0);
            ctorIL.Emit(OpCodes.Call, baseConstructor);
            ctorIL.Emit(OpCodes.Nop);
            ctorIL.Emit(OpCodes.Nop);
            ctorIL.Emit(OpCodes.Ret);


            tb.AddInterfaceImplementation(interfaceType);

            MethodBuilder mbIM = tb.DefineMethod(interfaceType.Name + "." + interfaceMethod.Name,
                MethodAttributes.Private | MethodAttributes.HideBySig |
                MethodAttributes.NewSlot | MethodAttributes.Virtual |
                MethodAttributes.Final,
                returnType,
                interfaceMethodArgs);
            ILGenerator genIM = mbIM.GetILGenerator();
            // ToDo
            genIM.Emit(OpCodes.Call, classMethod);
            genIM.Emit(OpCodes.Ret);


            tb.DefineMethodOverride(mbIM, interfaceMethod);

            Type t = tb.CreateType();

            return Activator.CreateInstance(t) as T;
        }

    }

    static void Main(string[] args)
    {
        IA a;
        a = new GeneratedA();
        a.DoInterface("0", true, 2, 3, new List<float>() { 4 }, "5", 6);
        a = Generator.Create<IA>();
        a.DoInterface("0", true, 2, 3, new List<float>() { 4 }, "5", 6);
    }
}

每当我尝试填写注释“ToDo”时,都会收到错误“公共语言运行时检测到无效程序”。

我请求帮助调用 DoClass 方法。

Thanks


To call DoClass您需要提供参数的方法,只需Call classMethod是行不通的。

第一个参数当然是“this”引用:

genIM.Emit(OpCodes.Ldarg_0);

第二个参数是对象数组。params是编译器功能,如果您自己构建代码 - 您必须将其视为params不在这里。我的意思是 - 虽然

 DoClass();

当你用代码编写它时是合法的 - 编译为:

DoClass(new object[0]);

因此,当您发出此调用时 - 您应该始终提供对象数组参数,不能省略它。

将对象数组压入堆栈:

// push array length (0, for example) to stack
genIM.Emit(OpCodes.Ldc_I4_0); 
// push new array with length given by the above value (0)
genIM.Emit(OpCodes.Newarr, typeof(object)); 

此时您的代码将编译并运行良好。这类似于:

public class GeneratedA : A, IA
{
    public void DoInterface(string arg0, bool arg1, int arg2, object arg3, List<float> arg4, params object[] otherArgs)
    {
        DoClass();
    }
}

如果你想传递所有参数DoInterface,这需要更多的工作。我将提供几个例子。传递第一个参数 (string arg0):

genIM.Emit(OpCodes.Dup);
// push index to store next element at (0)
genIM.Emit(OpCodes.Ldc_I4_0);
// push first argument (arg0 of DoInterface) to stack
genIM.Emit(OpCodes.Ldarg_1);
// store element in array at given index (yourArguments[0] = arg0)
genIM.Emit(OpCodes.Stelem_Ref);

传递第二个参数:

genIM.Emit(OpCodes.Dup);
// push index to store next element at (1)
genIM.Emit(OpCodes.Ldc_I4_1);
// push arg2
genIM.Emit(OpCodes.Ldarg_2);
// box, because boolean is value type, and you store it in object array
genIM.Emit(OpCodes.Box, typeof(bool));
// store in array (yourArguments[1] = (object) arg2
genIM.Emit(OpCodes.Stelem_Ref);

等等。

当您将参数推入数组时,不要忘记更改其长度以反映参数的数量:

// push array length - 6
genIM.Emit(OpCodes.Ldc_I4_6); 
// push new array with length given by the above value (6)
genIM.Emit(OpCodes.Newarr, typeof(object)); 

另请注意,您可能想要更改:

TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, baseType);

to

TypeBuilder tb = mb.DefineType("GeneratedA", TypeAttributes.Public, classType);

或者只是更改为baseType = typeof(A),因为您想继承生成的类A,不是来自object.

使用前 2 个参数发出调用的完整代码:

ILGenerator genIM = mbIM.GetILGenerator();            
genIM.Emit(OpCodes.Ldarg_0);   
genIM.Emit(OpCodes.Ldc_I4_2);
genIM.Emit(OpCodes.Newarr, typeof(object));

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_0);
genIM.Emit(OpCodes.Ldarg_1);
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Dup);
genIM.Emit(OpCodes.Ldc_I4_1);
genIM.Emit(OpCodes.Ldarg_2);
genIM.Emit(OpCodes.Box, typeof(bool));
genIM.Emit(OpCodes.Stelem_Ref);

genIM.Emit(OpCodes.Call, classMethod);
genIM.Emit(OpCodes.Ret);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

IL 使用 Reflection.Emit 调用带有 params object[] 参数的方法 的相关文章

随机推荐

  • Kendo 自动完成显示两个建议列表

    我的 Kendo 自动完成控件成功检索 Json 列表 不幸的是 它调用了 MVC 控制器方法两次并创建了两个建议列表 重复列表直接显示在第一个列表后面 当从第一个建议列表中选择一个值时 该列表会消失 但重复列表仍然可见 我正在使用自动完成
  • Angular“=”范围不适用于驼峰命名法

    我是指令的范围属性 我使用时效果很好show作为属性名称 span span
  • 如何在 pip 安装期间编译 C++ 依赖项?

    我想让我的 python 代码可以使用 pip 但是 我的代码依赖于另一个不可 pip 的库 所以 当用户调用时我需要以某种方式编译源代码pip install 我怎样才能做到这一点 我无法通过简单的谷歌搜索找到好的参考资料 我建议看看 l
  • 使用请求对象 Flask 获取 json 响应

    网络服务 app route get details def getDetails cur execute select from employee rows cur fetchall columns desc 0 for desc in
  • CSS / HTML 导航和徽标位于同一行

    我不知道如何将它们放在同一条线上 http codepen io anon pen dovZdQ http codepen io anon pen dovZdQ div class navigation bar div img src lo
  • 如何修复/调整 ggplot geom_tile 中每个带的宽度

    这是我的问题的示例数据 sampledata lt matrix c 1 60 1 60 rep 0 1 each 60 sample 1 3 120 replace T ncol 3 colnames sampledata lt c Ti
  • 如何进行递归子文件夹搜索并返回列表中的文件?

    我正在编写一个脚本 以递归方式遍历主文件夹中的子文件夹并构建特定文件类型的列表 我的脚本有问题 目前设置如下 for root subFolder files in os walk PATH for item in files if ite
  • Jquery AJAX:服务器端验证失败时如何显示Flash错误消息?

    我正在使用 Jquery 表单插件通过 ajax 提交表单 我已经在我的模型中的服务器端设置了验证 现在 当验证失败时 我想使用 ajax 向用户显示相同的 flash error 消息 如果验证成功 我可以显示 flash notice
  • Xcode 卡在索引上

    我已经工作了两个月的项目无缘无故停止工作 因为 Xcode 卡在 索引 上 我无法再构建该项目了 如果我尝试构建 Xcode 就会冻结 我必须强制退出 这种情况仅发生在该项目中 我尝试清理所有派生数据 但没有帮助 我正在使用 Xcode 4
  • jqgrid 更改单元格值并保持编辑模式

    我在网格中使用内联编辑 在某些情况下我想更改列内单元格的值 我用 setCell 更改它 效果很好 我的问题是 更改后 单元格失去了编辑模式 而该行的所有其他单元格都处于编辑模式 我想在更改单元格后将其保持在编辑模式 现在我所做的是保存该行
  • 种子中的 DHT

    我正在编写一个 P2P 实现 我希望将其去中心化 然而我在掌握如何做时遇到了一些困难DHT https en wikipedia org wiki Distributed hash table在像 BitTorrent 这样的协议中是有效的
  • 帮助正确计算atan2

    我需要计算线之间的角度 我需要计算atan 所以我正在使用这样的代码 static inline CGFloat angleBetweenLinesInRadians2 CGPoint line1Start CGPoint line1End
  • python中“追加”和“+”有什么区别? [复制]

    这个问题在这里已经有答案了 我不知道有什么区别f and g 功能中f 每当调用函数时 列表 L 就会累积 但在功能上g 它不是 def f a L L append 2 print L def g a L L L 2 print L pr
  • SQL Server 2008中的递归同表查询

    我在 SQL Server 2008 数据库中有下表 Id Name ParentFolder 1 Europe NULL 2 Asia NULL 3 Germany 1 4 UK 1 5 China 2 6 India 2 7 Scotl
  • echo 函数跳转到 Div 之外

    我创建了一个用于 gettext 翻译的函数 该函数位于头文件中 function ex text echo gettext text 当我使用函数 ex 时它会翻译该函数中的任何文本 效果很好 尽管当我在另一个内部有 div 的函数中使用
  • 使用 Apache Lucene 对 MySQL 数据库建立索引,并保持它们同步

    当MySQL中添加一个新项目时 它也必须被Lucene索引 当现有项目从 MySQL 中删除时 它也必须从 Lucene 的索引中删除 这个想法是编写一个脚本 通过调度程序 例如 CRON 任务 每 x 分钟调用一次 这是保持 MySQL
  • 简单的 Perl websocket 客户端

    我正在尝试用 Perl 编写一个简单的 websocket 客户端 use Protocol WebSocket Client my client Protocol WebSocket gt new url gt ws myserver p
  • 使用多核的 Numpy np.einsum 数组乘法

    我用MKL编译了numpy 1 6 2和scipy 希望有更好的性能 目前我有一个严重依赖 np einsum 的代码 并且我被告知 einsum 不适用于 MKL 因为几乎没有矢量化 所以我想用 np dot 和切片重新编写一些代码 只是
  • 预训练 Transformer 模型的配置更改

    我正在尝试为重整变压器实现一个分类头 分类头工作正常 但是当我尝试更改配置参数之一 config axis pos shape 即模型的序列长度参数时 它会抛出错误 Reformer embeddings position embeddin
  • IL 使用 Reflection.Emit 调用带有 params object[] 参数的方法

    我正在编写一个需要稍后类型构建的库 库使用平台 Net core 2 0 我使用 Reflection Emit 生成的某些类型存在问题 public class GeneratedA A IA public void DoInterfac