C#, dynamic generation of Struct and Enum in an .Net Assembly

310 Views Asked by At

Brief: I have generated dynamically many Enums and saved them in an dynamic Assembly. I have tried to load this Assembly and use its Types(Enums) as Fields of generated struct. Those structs will be save in a diiferent assembly.

But there is a problem during the save-process of the new Assembly(of Structs)

Here is the code I actually use:

    public List<Type> CreateEnum()
    {
        AppDomain currentDomain = AppDomain.CurrentDomain;

        AssemblyName aName = new AssemblyName("AssemblyTest");
        AssemblyBuilder assemblyBuilder = currentDomain.DefineDynamicAssembly(
            aName, AssemblyBuilderAccess.RunAndSave);

        ModuleBuilder moduleBuilder = assemblyBuilder.DefineDynamicModule(aName.Name, aName.Name + ".dll");

         for (int i = 0; i < list_Datatype_Typ.Count; i++)
        {
            if (list_SingleValues != null && list_SingleValues[i] != "")
            {
                if (tmp == eb_count)
                {
                    list_enumBuilder.Add( moduleBuilder.DefineEnum(list_Datatype_Id[i].ToString(),          // record a new Enum in the Module (Assembly, contains only one module)
                                                  TypeAttributes.Public, list_RealDatatype[i]) );
                    tmp++;  // variable to check if the previous Enum is completed
                }
                // Check if is a SingleValue
                if ((((i < list_Datatype_Id.Count - 1) && (list_Datatype_Id[i] == list_Datatype_Id[i + 1]))
                    || ((i > 0) && list_Datatype_Id[i] == list_Datatype_Id[i - 1]))
                    && (list_Datatype_Typ[i].ToString() != "ValueRange" && list_Datatype_Typ[i].ToString() != "RecordValueRange" && list_Datatype_Typ[i].ToString() != "none"))
                {
                    list_enumBuilder[eb_count].DefineLiteral(list_Datatype_Typ[i].ToString(), Convert.ChangeType(list_SingleValues[i].ToString(), list_RealDatatype[i]));

                    // check if those singlevalues with this type were all written
                    if (((i < list_Datatype_Id.Count-1) && list_Datatype_Id[i] != list_Datatype_Id[i+1]) || (i == list_Datatype_Id.Count - 1))
                    {
                        // Create the type and save the assembly.
                        list_EnumType.Add(list_enumBuilder[eb_count].CreateType());
                        eb_count++;                                                                         // At the end of an Enum... let's increment the  EnumBuilder_count
                    }
                }
            }
        }
        assemblyBuilder.Save(aName.Name + ".dll"); // Save the Assembly after all the Enum-Types were created
        return list_EnumType;                                                                           // return the list of enum-types
    }


    public List<Type> CreateStruct()
    {
      // Create assembly and module
        var assemblyName = new AssemblyName("AssemblyLeuze_Record");
        var assemblyBuilder = AppDomain.CurrentDomain.
            DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave);
        var moduleBuilder = assemblyBuilder.
            DefineDynamicModule(assemblyName.Name, assemblyName.Name + ".dll");

        // Find MarshalAsAttribute's constructor by signature, then invoke
        var ctorParameters = new Type[] { typeof(UnmanagedType) };
        var ctorInfo = typeof(MarshalAsAttribute).GetConstructor(ctorParameters);

        var fields = typeof(MarshalAsAttribute).GetFields(BindingFlags.Public | BindingFlags.Instance);
        var sizeConst = (from f in fields
                            where f.Name == "SizeConst"
                            select f).ToArray();
        var marshalAsAttr = new CustomAttributeBuilder(ctorInfo,
            new object[] { UnmanagedType.ByValTStr }, sizeConst, new object[] { 5 });


        //**************************************************************************************
        // Using the Enums.. to test ********************************************
        Assembly ass = System.Reflection.Assembly.LoadFrom("AssemblyLeuze.dll");
        //Type a = ass.GetType("DT_0_29");
        Enum enumObj = (Enum)Activator.CreateInstance(ass.GetType("DT_0_29"));
        //enumObj i;
        string[] enums = (from type in ass.GetTypes()                                                   // get all the Enum-Names (will use it down in the conditions)              
                        select type.Name).ToArray();

        for (int i = 0; i < list_Datatype.Count; i++)                                      // Read only recordT datatypes
        {
            // get all the RecordTs
            if (list_Datatype != null && list_Datatype[i] != "" && Convert.ToBoolean(list_IsRecordItem[i].ToString()))
            {
                if (tmp == tb_count)    
                {
                    // Open a new Type for definition
                    list_typeBuilder.Add( moduleBuilder.DefineType(list_Datatype_Id[i].ToString(), 
                                                                    TypeAttributes.Public |
                                                                    TypeAttributes.Sealed |
                                                                    TypeAttributes.ExplicitLayout |
                                                                    TypeAttributes.Serializable |
                                                                    TypeAttributes.AnsiClass,
                                                                    typeof(ValueType)) );
                    tmp++;  // variable to check if the previous Enum is completed
                }

                // Record the Fields

                if (Other Types)                            // Because of the order in the dataTable, read Datatype_Id instead of Datatype_Typ
                {
                    // ...
                }  
                else if (!(enums.Contains<string>(list_Datatype_Id[i].ToString())))
                {
                    list_FieldBuilder.Add(list_typeBuilder[tb_count].DefineField(
                                    list_Datatype_Id[i],                                        // the name of the struct-Feld
                                    list_RealDatatype[i],                                       // the datatype of the struct-Feld
                                    FieldAttributes.Public));
                    list_FieldBuilder[fb_count].SetCustomAttribute(marshalAsAttr);
                    list_FieldBuilder[fb_count].SetOffset(fb_count);
                }
                fb_count++;                                                                     // first incrementaton of fb_count

                // check if those singlevalues with this type were all written
                if (((i < list_Datatype.Count-1) && list_Datatype[i] != list_Datatype[i+1]) || (i == list_Datatype.Count-1))
                {
                    list_StructType.Add(list_typeBuilder[tb_count].CreateType());               // Create the type and save the assembly.
                    isVal.Add(list_StructType[tb_count].IsValueType);                           // true
                    fb_count = 0;                                                               // reset fb_count at the end of the struct
                    list_FieldBuilder.Clear();                                                  // Reset the list of Fields by clearing
                    tb_count++;                                                                 // At the end of a Struct... let's increment the  EnumBuilder_count
                }

            }
        }
        assemblyBuilder.Save(assemblyName.Name + ".dll");                                       // Save the Assembly after all the Enum-Types were created
        return list_StructType;                                                                 // return a list which contains struct-types
    }

Issue: "Here is the error message"

System.TypeLoadException: 'The type' DT_TTT 'of the assembly' AssemblyTest, Version = 0.0.0.0, Culture = neutral, PublicKeyToken = null 'could not be loaded because it contains an object field at Offset 1 that is misaligned or from one Overlapping field that is not an object field. '

I don't know if if due to and error during the loading, or my Assembly containing the Enums were wrong generated, or the is another way to generate those struct.

Thank you.

0

There are 0 best solutions below