lundi 12 mars 2018

How to use incompleted types in reflection?

I want to generate dynamically assembly, which can have functions with different structures. If to be more accurate, these functions can be recursive, they can call other functions within the same assembly etc. I found System.Reflection module which theoretically provides tools to do this. But in practice I have encountered many drawbacks in this one. For example - I cannot generate recursive functions via TypeBuilder and MethodBuilder classes, because exception will be thrown (usage of incomplete types). I learned that I can generate selfrecursive functions via IlGenerator - but it is too painfull way for me - I hoped that there is more easy way to do this? Here is my program which demonstrates problem (at generation of Fact method raises exception with message 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();
        }
    }
}

I appreciate any ideas how to cope with this.





Aucun commentaire:

Enregistrer un commentaire