c# - 如何在反射中使用不完整的类型?

标签 c# reflection system.reflection

我想动态生成程序集,它可以有不同结构的功能。更准确地说,这些函数可以递归,它们可以调用同一程序集中的其他函数等。我发现 System.Reflection 模块理论上提供了执行此操作的工具,但在实践中我遇到了这种方法有很多缺点。例如 - 我无法通过 TypeBuilderMethodBuilder 类生成递归函数,因为会抛出异常(使用不完整的类型)。我了解到我可以通过 IlGenerator 生成自递归函数 - 但它太麻烦了 - 我希望有更简单的方法来做到这一点。

这是我的程序,它演示了这个问题(在生成方法 Fact 时抛出以下异常:

Exception thrown: 'System.NotSupportedException' in mscorlib.dll 
Additional information: Specified method is not supported..

代码:

using System;
using System.Reflection;
using System.Reflection.Emit;
using System.Linq.Expressions;

namespace GenericFuncs
{
    public class ProgramBuilder
    {
        public Type createMyProgram()
        {
            var assmName = new AssemblyName("DynamicAssemblyExample");
            var assmBuilder = AppDomain.CurrentDomain.DefineDynamicAssembly(assmName, AssemblyBuilderAccess.RunAndSave);
            var moduleBuilder = assmBuilder.DefineDynamicModule(assmName.Name, assmName.Name + ".dll");
            var myProgramType = buildMyProgram(moduleBuilder, moduleBuilder.DefineType("MyProgram", TypeAttributes.Public));
            assmBuilder.Save(assmName.Name + ".dll");
            return myProgramType;
        }        

        private Type buildMyProgram(ModuleBuilder mb, TypeBuilder programBuilder)
        {
            buildFactFunction2(mb, mb.GetType("MyProgram"), programBuilder.DefineMethod("InfLoop", MethodAttributes.Public | MethodAttributes.Static));
            buildFactFunction(mb, mb.GetType("MyProgram"), programBuilder.DefineMethod("Fact", MethodAttributes.Public | MethodAttributes.Static));
            return programBuilder.CreateType();
        }

        private void buildFactFunction(ModuleBuilder mb, Type program_type, MethodBuilder methodBuilder)
        {
            var param = Expression.Parameter(typeof(int), "n");
            var lambda = Expression.Lambda(Expression.Call(methodBuilder, param), param);
            lambda.CompileToMethod(methodBuilder);
        }

        static public void my_print(string s)
        {
            Console.WriteLine(s);
        }

        private void buildFactFunction2(ModuleBuilder mb, Type program_type, MethodBuilder methodBuilder)
        {
            var il = methodBuilder.GetILGenerator();
            il.Emit(OpCodes.Ldstr, "a");
            il.Emit(OpCodes.Call, typeof(ProgramBuilder).GetMethod("my_print"));
            il.Emit(OpCodes.Call, methodBuilder);
            il.Emit(OpCodes.Ret);
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var pbuilder = new ProgramBuilder();
            var ptype = pbuilder.createMyProgram();
            Console.ReadLine();
        }
    }
}

感谢任何帮助。

最佳答案

Expressions和 C# 中的反射有其局限性(尽管对于简单的用例仍然非常强大)。据我所知,Emit如果您需要您描述的功能(甚至是发射程序集的基本要求),这就是您要走的路。

几年前,我使用 RunSharp在一些最小的动态代码生成用例中非常有效。它带走了大部分的 IL 痛苦。例如,在 this code 中我在运行时创建了一个代理包装器。

你也可以看看 Castle Project用于他们的代码生成,例如,他们的 DynamicProxy很受欢迎。

关于c# - 如何在反射中使用不完整的类型?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49231513/

相关文章:

c# - 有没有办法找到 C# 程序集引用的类型?

c# - 在 C# 中有条件地实例化一个类

c# - C# 中多次转换的规则是什么?

c# - 选择排序算法排序错误

java - 使用反射调用方法时传递什么对象

c# - 如何将用户输入的字符串作为字段名传递以访问对象中的字段?

c# - 通过代码,我怎样才能让硬盘驱动器进入休眠状态

c# - 在 asp.net Portable.Licensing 中,.WithMaximumUtilization(1) 的含义和用途是什么?

c# - 反射获取 `Parent`对象

c# - 使用反射以 IList<T> 形式检索 NHibernate.Collections.Generic.PersistentGenericBag