2016-08-18 97 views
1

我试图使用CodeDom创建一个复杂的对象。现在我有创建简单的对象,如无问题:CodeDom - 创建具有对象数组属性的对象

public class MyClass 
{ 
    public FirstName {get; set;} 
    public LastName {get; set;} 
} 

public class Subclass 
{ 
    public string SubProperty {get; set;} 
} 

但我有一些麻烦,创建以下:

public class MyClass 
{ 
    public string FirstName {get; set;} 
    public string LastName {get; set;} 
    public Subclass[] SubClasses {get; set;} 
} 

这是我目前的执行。

public class cls_Code_Generator 
    { 
     private CodeNamespace CodeNamespace { get; set; } 
     private JSchema JsonSchema { get; set; } 
     public cls_Code_Generator() 
     { 
      CodeNamespace = new CodeNamespace("GeneratedCode"); 
      CodeNamespace.Imports.Add(new CodeNamespaceImport("System")); 
     } 
    public Assembly CreateType(JSchema schema) 
    { 
     JsonSchema = schema; 
     CodeTypeDeclaration CodeType = new CodeTypeDeclaration(); 
     CodeType.Name = "RuntimeType"; 
     CodeType.IsClass = true; 
     CodeType.Attributes = MemberAttributes.Public; 

     CodeNamespace.Types.Add(CodeType); 

     CodeType = GetFields(CodeType); 

     CodeCompileUnit CodeUnit = new CodeCompileUnit(); 
     CodeUnit.ReferencedAssemblies.AddRange(GetReferenceList()); 
     CodeUnit.Namespaces.Add(CodeNamespace); 
     return CreateTypeInMemory(CodeUnit); 
    } 

    private Assembly CreateTypeInMemory(CodeCompileUnit codeUnit) 
    { 
     Assembly CompiledAssembly = null; 

     CompilerParameters CompilerParams = new CompilerParameters(); 
     CompilerParams.ReferencedAssemblies.AddRange(new[] { "System.dll" }); 
     CompilerParams.GenerateInMemory = true; 
     CompilerParams.GenerateExecutable = false; 

     CSharpCodeProvider Compiler = new CSharpCodeProvider(); 
     CompilerResults Results = Compiler.CompileAssemblyFromDom(CompilerParams, codeUnit); 

     if (Results.Errors != null && Results.Errors.Count == 0) 
     { 
      CompiledAssembly = Results.CompiledAssembly; 
     } 
     return CompiledAssembly; 
    } 

    private CodeTypeDeclaration GetFields(CodeTypeDeclaration CodeType) 
    { 
     CodeType.Members.AddRange(GetGeneratedFieldCollection()); 
     return CodeType; 
    } 

    private CodeTypeMember[] GetGeneratedFieldCollection() 
    { 
     var codeMemberFieldList = new List<CodeMemberField>(); 
     foreach (var property in JsonSchema.Properties) 
     { 
      codeMemberFieldList.Add(new CodeMemberField 
      { 
       Type = new CodeTypeReference(JSchemaTypeHelper.GetJSchemaSystemType(property.Value.Type)), 
       Name = property.Key, 
       Attributes = MemberAttributes.Public 
      }); 

     } 
     return codeMemberFieldList.ToArray(); 
    } 

    private string[] GetReferenceList() 
    { 
     List<string> references = new List<string>(); 
     references.AddRange(new string[] { "System", "System.Collections", "System.Collections.Generic" }); 
     return references.ToArray(); 
    } 

} 
+0

是否因为缺少子类的定义? – SzymonK

+0

请显示您的代码。 –

+0

@BradleyUffner添加了我目前的实现。 – R007

回答

0

所以我最终搞清楚了,我不得不先生成子类,然后使用生成的子类的类型创建一个List。此处的实现将允许您创建原始类型,对象和列表的字段。

public Assembly CreateType(JSchema schema) 
    { 
     CodeTypeDeclaration CodeType = new CodeTypeDeclaration(); 
     CodeType.Name = schema.Id.ToString(); 
     CodeType.IsClass = true; 
     CodeType.Attributes = MemberAttributes.Public; 

     CodeNamespace.Types.Add(CodeType); 

     CodeType = GetFields(CodeType, schema); 

     CodeCompileUnit CodeUnit = new CodeCompileUnit(); 
     CodeUnit.ReferencedAssemblies.AddRange(GetReferenceList()); 
     CodeUnit.Namespaces.Add(CodeNamespace); 
     return CreateTypeInMemory(CodeUnit); 
    } 

    private Assembly CreateTypeInMemory(CodeCompileUnit codeUnit) 
    { 
     Assembly CompiledAssembly = null; 

     CompilerParameters CompilerParams = new CompilerParameters(); 
     CompilerParams.ReferencedAssemblies.AddRange(new[] { "System.dll" }); 
     CompilerParams.GenerateInMemory = true; 
     CompilerParams.GenerateExecutable = false; 

     CSharpCodeProvider Compiler = new CSharpCodeProvider(); 
     CompilerResults Results = Compiler.CompileAssemblyFromDom(CompilerParams, codeUnit); 

     if (Results.Errors != null && Results.Errors.Count == 0) 
     { 
      CompiledAssembly = Results.CompiledAssembly; 
     } 
     return CompiledAssembly; 
    } 

    private CodeTypeDeclaration GetFields(CodeTypeDeclaration CodeType, JSchema schema) 
    { 
     CodeType.Members.AddRange(GetGeneratedFieldCollection(schema)); 
     return CodeType; 
    } 

    private CodeTypeMember[] GetGeneratedFieldCollection(JSchema schema) 
    { 
     var codeMemberFieldList = new List<CodeMemberField>(); 
     foreach (var property in schema.Properties) 
     { 
      if (property.Value.Type.ToString() != "Array, Null" && property.Value.Type.ToString() != "Object, Null") 
      { 
       codeMemberFieldList.Add(new CodeMemberField 
       { 
        Type = new CodeTypeReference(JSchemaTypeHelper.GetJSchemaSystemType(property.Value.Type)), 
        Name = property.Key, 
        Attributes = MemberAttributes.Public 
       }); 
      } 
      else if(property.Value.Type.ToString() == "Array, Null") 
      { 
       var generatedAssembly = CreateType(property.Value.Items.FirstOrDefault()); 
       var type = GetTypeFromAssembly(generatedAssembly, property); 
       Type listType = typeof(List<>).MakeGenericType(type); 

       var codeMemberField = new CodeMemberField 
       { 
        Type = new CodeTypeReference(listType), 
        Name = property.Key, 
        Attributes = MemberAttributes.Public 
       }; 
       codeMemberFieldList.Add(codeMemberField); 
      } 
      else 
      { 
       var generatedAssembly = CreateType(property.Value.Items.FirstOrDefault()); 
       var type = GetTypeFromAssembly(generatedAssembly, property); 

       var codeMemberField = new CodeMemberField 
       { 
        Type = new CodeTypeReference(type), 
        Name = property.Key, 
        Attributes = MemberAttributes.Public 
       }; 
       codeMemberFieldList.Add(codeMemberField); 
      } 
     } 
     return codeMemberFieldList.ToArray(); 
    } 

    private string[] GetReferenceList() 
    { 
     List<string> references = new List<string>(); 
     references.AddRange(new string[] { "System", "System.Collections", "System.Collections.Generic" }); 
     return references.ToArray(); 
    } 

    private Type GetTypeFromAssembly(Assembly generatedAssembly, KeyValuePair<string, JSchema> property) 
    { 
     string definedTypeName = property.Value.Items.FirstOrDefault().Id.ToString(); 

     return generatedAssembly.DefinedTypes 
      .FirstOrDefault(definedtype => definedtype.Name == definedTypeName); 
    }