2017-03-16 39 views
0

Hiho, 我想在给定的xml的基础上生成一个类,要做到这一点我使用Reflection.Emit,我有以下到目前为止方法:创建动态嵌套类,并将其添加为动态类型中的属性

private static AssemblyBuilder GetAssemblyBuilder() 
    { 
     AssemblyBuilder assemblyBuilder; 

     AssemblyName assemblyName = new AssemblyName(Constants.ClassGenerator.ASSEMBLY_NAME); 
     if (Assemblies.TryGetValue(assemblyName, out assemblyBuilder)) 
     { 
      return assemblyBuilder; 
     } 

     AppDomain currentDomain = AppDomain.CurrentDomain; // Thread.GetDomain(); 
     assemblyBuilder = currentDomain 
       .DefineDynamicAssembly(assemblyName, AssemblyBuilderAccess.RunAndSave); 

     if (!Assemblies.TryAdd(assemblyName, assemblyBuilder)) 
     { 
      throw new Exceptions.ClassGeneratorException("The assembly cannot be added to the dictionary."); 
     } 

     return assemblyBuilder; 
    } 

private static ModuleBuilder GetModuleBuilder(AssemblyBuilder inAssemblyBuilder) 
    { 
     ModuleBuilder module = inAssemblyBuilder.DefineDynamicModule(Constants.ClassGenerator.MODULE_NAME, 
                    $"{Constants.ClassGenerator.MODULE_NAME}.dll"); 

     return module; 
    } 

public static FormatBase CreateType(XmlConfiguration inConfiguration) 
    { 
     ModuleBuilder module = GetModuleBuilder(GetAssemblyBuilder()); 

     TypeBuilder typeBuilder = module.DefineType(inConfiguration.EdiFactType, 
                TypeAttributes.Public | 
                TypeAttributes.Class | 
                TypeAttributes.Serializable, typeof (FormatBase)); 

     AddDataContractAttribute(typeBuilder); 

     //<Adding Properties> 
     MapProperties(typeBuilder, inConfiguration.XmlProperties); 

     //<Generate the type> 
     Type t = typeBuilder.CreateType(); 
     return (FormatBase) Activator.CreateInstance(t); 
    } 

public static void MapProperties(TypeBuilder inTypeBuilder, List<XmlProperty> inProperties) 
    { 
     foreach (XmlProperty xmlProperty in inProperties) 
     { 
      if (xmlProperty.Children.Any()) 
      { 
       TypeBuilder newClass = CreateClass(inTypeBuilder, xmlProperty); 

       MapProperties(newClass, xmlProperty.Children); 

       newClass.CreateType(); 

       CreateProperty(inTypeBuilder, newClass); 
      } 
      else 
      { 
       PropertyBuilder propertyElement = CreateProperty(inTypeBuilder, xmlProperty); 
      } 
     } 
    } 

public static TypeBuilder CreateClass(TypeBuilder inParentBuilder, XmlProperty inXmlProperty) 
    { 
     TypeBuilder typeBuilder = inParentBuilder.DefineNestedType(inXmlProperty.PropertyName, TypeAttributes.Public | 
                          TypeAttributes 
                            .NestedPublic | 
                          TypeAttributes 
                            .Serializable); 

     AddDataContractAttribute(typeBuilder); 

     return typeBuilder; 
    } 

到目前为止一切正常,问题是当我尝试添加一个新创建的类作为类型,我产生一个属性:

private static PropertyBuilder CreateProperty(TypeBuilder inParentTypeBuilder, TypeBuilder inTypeBuilder) 
    { 
     Type propertyType = inTypeBuilder.CreateType(); 

     PropertyBuilder propertyBuilder = 
       inParentTypeBuilder.DefineProperty(propertyType.Name, 
                PropertyAttributes.None, 
                propertyType, 
                new[] {propertyType}); 

     FieldBuilder field = inParentTypeBuilder.DefineField($"_{propertyBuilder.Name.ToLower()}", 
                  propertyType, 
                  FieldAttributes.Private); 

     GetMethodBuilder(inParentTypeBuilder, propertyBuilder, field); 
     SetMethodBuilder(inParentTypeBuilder, propertyBuilder, field); 

     //SetAttribute(propertyBuilder, inXmlProperty); 

     return propertyBuilder; 
    } 

抛出一个System.TypeLoadException,说我的类型不能被加载,并在我呼入的地方引发ParentTypeBuilder.DefineProperty。

任何好的撒玛利亚人-Reflection.emit-guru能帮助我吗?

回答

0

我“固定”它使类不嵌套。

这不是一个解决方案,但它的工作。

private TypeBuilder CreateClass(XmlProperty inXmlProperty = null) 
    { 
     if (inXmlProperty == null) 
     { 
      //It's root class (CONTRL; UTILMD; INVOC; ETC) 
      TypeBuilder rootTypeBuilder = ModuleBuilder.DefineType(Configuration.EdiFactType, 
                    TypeAttributes.Public | 
                    TypeAttributes.Class | 
                    TypeAttributes.Serializable); 
      RootClass = rootTypeBuilder; 

      TypeController.SetClassAttributes(RootClass); 

      return rootTypeBuilder; 
     } 

     //Nested class (Nachricht, Vorgang, etc) 
     TypeBuilder typeBuilder = ModuleBuilder.DefineType(inXmlProperty.PropertyName, TypeAttributes.Public | 
                         TypeAttributes.Class | 
                         TypeAttributes.Serializable); 

     TypeController.SetClassAttributes(typeBuilder, inXmlProperty); 

     return typeBuilder; 
    }