CodeDom - 创建具有 属性 个对象数组的对象

CodeDom - Create object that has a property of an array of objects

我正在尝试使用 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();
    }

}

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

    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);
    }