Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preserve serialization-order of members in CodeDOM

I know we can enforce generating the members within the classes in the same order as within the members-collection as stated on MSDN. However I look for some code that also adds a serialization-attribute providing the order of those members. So this is what I want the generator to create:

class MyClass
{
    [XmlElement("TheProperty", Order = 0]
    public int MyProperty { get; set; }
    [XmlElement("AnotherProperty", Order = 1]
    public int AnotherProperty { get; set; }
}

Currently I have an approach that loops the members of all types within my DOM and appends the attribute to the CustomAttributes-member of the current (public) property or field.

var types = code.Types.Cast<CodeTypeDeclaration>().Where(x => !x.IsEnum);
foreach (var members in types.Select(x => x.Members.Cast<CodeTypeMember>()))
{
    int i = 0;
    var propertiesAndFields = members.Where(x => (
            x.Attributes & MemberAttributes.Private) != MemberAttributes.Private
            && (x is CodeMemberField || x is CodeMemberProperty));
    foreach (CodeTypeMember member in propertiesAndFields)
    {
        var attr = member.CustomAttributes.Cast<CodeAttributeDeclaration>().FirstOrDefault(x => x.Name == "System.Xml.Serialization.XmlElementAttribute");
        if (attr == null)
        {
            attr = new CodeAttributeDeclaration("System.Xml.Serialization.XmlElementAttribute");
            member.CustomAttributes.Add(attr);
        }
        attr.Arguments.Add(new CodeAttributeArgument("Order", new CodePrimitiveExpression(i++)));

    }
}

However this seems quite hacky to me and I wonder if there were a member built into CodeDOM that creates the Order-attributes. I remember the Xsd-tool (which I want to extent with custom behaviour using CodeDOM and which uses the same classes and interfaces) is able to append those attributes.

EDIT: The codeDOM is created using the XmlSchemaImporter- and XmlCodeExporter-class as mentioned on MSDN:

XmlSchemas schemas = new XmlSchemas();
schemas.Add(schema);            
// Create the importer for these schemas.
XmlSchemaImporter importer = new XmlSchemaImporter(schemas);
// System.CodeDom namespace for the XmlCodeExporter to put classes in.
CodeNamespace code = new CodeNamespace(targetNamespace);
XmlCodeExporter exporter = new XmlCodeExporter(code);
// Iterate schema top-level elements and export code for each.
foreach (XmlSchemaElement element in schema.Elements.Values)
{
    // Import the mapping first.
    XmlTypeMapping mapping = importer.ImportTypeMapping(element.QualifiedName);
    // Export the code finally
    exporter.ExportTypeMapping(mapping);
}

I can´t see a way to provide the order-attributes here, this is why I want to set them after the DOM has already been created.

like image 819
MakePeaceGreatAgain Avatar asked Aug 02 '16 08:08

MakePeaceGreatAgain


1 Answers

There is no build in way in CodeDOM, the right way is to add XmlAttributes, but there is problem with them, because they don't gather along with inheritance. So is better to emit the properties in right order, then the xml serializer will serialize it in the right order(not guaranteed but I have tested it). Hope it works! :)

like image 60
Ivelin Ivanov Avatar answered Oct 31 '22 12:10

Ivelin Ivanov