C# 使用XmlSerializer反序列化和序列化XML时保持排序

C# 使用XmlSerializer反序列化和序列化XML时保持排序,c#,xml,xml-serialization,xmlserializer,C#,Xml,Xml Serialization,Xmlserializer,我有以下测试XML字符串: <?xml version="1.0" encoding="UTF-8"?> <test id="myid"> <b>b1</b> <a>a2</a> <a>a1</a> <b>b2</b> </test> 但是我不知道在序列化时如何按顺序排序。基本上没有XmlSerializer不支持此功能。如果要使用该选项,您需要使用XDo

我有以下测试XML字符串:

<?xml version="1.0" encoding="UTF-8"?>
<test id="myid">
 <b>b1</b>
 <a>a2</a>
 <a>a1</a>
 <b>b2</b>
</test>

但是我不知道在序列化时如何按顺序排序。

基本上没有
XmlSerializer
不支持此功能。如果要使用该选项,您需要使用
XDocument
XmlDocument
XmlReader
手动编写该选项,您可以使用
XmlSerializer
通过使用单个集合多次捕获
属性,每个所需的元素名称一次。由于使用单个集合反序列化两个元素,因此顺序将自动保留。但是,要使此工作正常,
XmlSerializer
必须能够在重新序列化时确定正确的元素名称。有两种方法可以实现这一点,如中所述:

  • 如果集合包含多态项,则可以使用构造函数将元素名称映射到具体的项类型。例如,如果有一系列元素可能是字符串或整数,如下所示:

    <Things>
       <string>Hello</string>
       <int>999</int>
    </Things>
    
    工作


    有关使用
    [xmlcoiceIdentifier]
    将具有不同名称的元素序列反序列化为同一类型的c#对象的更多示例,请参见示例或。

    出于好奇,是否有理由要求XML按特定顺序排列?我认为,只有在将数据加载或反序列化回对象后,才会使用排序。@gmiley我正在开发一个Office VSTO加载项,该加载项允许您添加自己的功能区选项卡,其中包含XML中定义的UI元素。xml元素顺序表示功能区UI顺序(例如:Save Button-Close Button或Close Button-Save Button),如果仔细想想-
    Test
    类不包含任何有关“原始”顺序的信息,因此,没有办法做到这一点。然后,您可以按照您的想法添加一个排序属性/元素,并对集合执行排序。忘记xml的顺序。@gmiley仅对a和b进行排序并不能使a之前有一个b元素(如我的示例中所示)。感谢您对同一属性的多个XmlElement属性的建议。我现在可以在属性中添加ElementName以映射到自定义类。
    <?xml version="1.0" encoding="utf-16"?>
    <test xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="myid">
      <a>a2</a>
      <a>a1</a>
      <b>b1</b>
      <b>b2</b>
    </test>
    
    [XmlRoot(ElementName="a")]
    public class A 
    {
        [XmlAttribute(AttributeName="order")]
        public string Order { get; set; }
        [XmlText]
        public string Text { get; set; }
    }
    
    [XmlRoot(ElementName="b")]
    public class B 
    {
        [XmlAttribute(AttributeName="order")]
        public string Order { get; set; }
        [XmlText]
        public string Text { get; set; }
    }
    
    [XmlRoot(ElementName="test")]
    public class Test 
    {
        [XmlElement(ElementName="a")]
        public List<A> A { get; set; }
        [XmlElement(ElementName="b")]
        public List<B> B { get; set; }
        [XmlAttribute(AttributeName="id")]
        public string Id { get; set; }
    }
    
    <Things>
       <string>Hello</string>
       <int>999</int>
    </Things>
    
    public class Things
    {
        [XmlElement(Type = typeof(string)),
        XmlElement(Type = typeof(int))]
        public List<object> StringsAndInts { get; set; }
    }
    
    public abstract class StringElementBase
    {
        [XmlText]
        public string Text { get; set; }
    
        public static implicit operator string(StringElementBase element)
        {
            return element == null ? null : element.Text;
        }
    }
    
    public sealed class A : StringElementBase
    {
    }
    
    public sealed class B : StringElementBase
    {
    }
    
    [XmlRoot(ElementName = "test")]
    public class Test
    {
        [XmlElement("a", Type = typeof(A))]
        [XmlElement("b", Type = typeof(B))]
        public List<StringElementBase> Items { get; } = new List<StringElementBase>();
    
        [XmlIgnore]
        // For convenience, enumerate through the string values of the items.
        public IEnumerable<string> ItemValues { get { return Items.Select(i => (string)i); } }
    
        [XmlAttribute(AttributeName = "id")]
        public string Id { get; set; }
    }