序列化为XML时重命名类

Ben*_*n L 5 c# xml-serialization xmlserializer

我正在尝试序列化Outer下面显示的类,并XElement从序列化的XML 创建一个.它有一个类型的财产Inner.我想更改Inner(to Inner_X)和Outer(to Outer_X)的名称.

class Program
{
    static void Main(string[] args)
    {
        using (MemoryStream memoryStream = new MemoryStream())
        {
            using (TextWriter streamWriter = new StreamWriter(memoryStream))
            {
                var xmlSerializer = new XmlSerializer(typeof(Outer));

                xmlSerializer.Serialize(streamWriter,  new Outer());

                XElement result = XElement.Parse(Encoding.ASCII.GetString(memoryStream.ToArray()));
            }
        }
    }
}

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new Inner();
    }

    public Inner InnerItem { get; set; }
}

[XmlType("Inner_X")]
public class Inner
{
}
Run Code Online (Sandbox Code Playgroud)

这创建了一个XElement如下所示:

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <InnerItem />
</Outer_X>
Run Code Online (Sandbox Code Playgroud)

我想要的是:

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
   <Inner_X />
</Outer_X>
Run Code Online (Sandbox Code Playgroud)

我想保留有关如何使用该类重命名类的信息.我以为我可以用XmlType属性做到这一点.但是,这会被忽略,而是使用属性名称.

我看这里这里,其它地方,并且觉得这应该工作.我错过了什么?

澄清

通过"保留关于如何使用该类重命名类的信息",我的意思是该术语Inner_X应该只出现在Inner类中.它不应该出现在Outer课堂上.

dbc*_*dbc 4

序列化类型时XmlSerializer,类型本身控制为其属性创建的元素的名称。即,属性名称将成为元素名称,除非被静态覆盖XmlElementAttribute.ElementNameXmlTypeAttribute.TypeName通常,仅当所应用的类型的实例未序列化为某些包含类型的属性时(例如,当它是根元素时,或者当它包含在以下集合中时),才控制元素名称:使用外部容器元素进行序列化。这种设计可以避免在给定类型中存在多个相同类型的属性的情况下发生名称冲突。

但是,多态属性类型有一个例外。对于这些,XmlSerializer可以选择使用每个可能的多态类型的 XML 类型名称作为元素名称,从而标识创建元素的实际 C# 类型。要启用此功能,必须[XmlElement(typeof(TDerived))]向属性添加多个属性,每个属性对应一种可能的类型TDerived

您可以使用此功能通过引入伪多态代理属性来生成所需的 XML:

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new Inner();
    }

    [XmlIgnore]
    public Inner InnerItem { get; set; }

    [XmlElement(typeof(Inner))]
    [XmlElement(typeof(object))]
    [Browsable(false), EditorBrowsable(EditorBrowsableState.Never), DebuggerBrowsable(DebuggerBrowsableState.Never)]
    public object InnerItemXmlProxy
    {
        get
        {
            return InnerItem;
        }
        set
        {
            InnerItem = (Inner)value;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后输出就是你所需要的:

<Outer_X xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Inner_X />
</Outer_X>
Run Code Online (Sandbox Code Playgroud)

原型小提琴

但是,正如 @evk 评论的那样,如果您的Outer类包含同一类型的多个属性,则无法完成此操作。

需要考虑的另一种选择:如果您只是不想"Inner_X"在多个位置(即在[XmlType(string name)][XmlElement(string name)]属性中)手动复制类型名称字符串,您可以通过将类型名称集中为public const

[XmlType(Outer.XmlTypeName)]
public class Outer
{
    public const string XmlTypeName = "Outer_X";

    public Outer()
    {
        this.InnerItem = new Inner();
    }

    [XmlElement(Inner.XmlTypeName)]
    public Inner InnerItem { get; set; }
}

[XmlType(Inner.XmlTypeName)]
public class Inner
{
    public const string XmlTypeName = "Inner_X";
}
Run Code Online (Sandbox Code Playgroud)

更新

我刚刚注意到你的评论我打算 Inner 是一个抽象基类,它的每个子类将序列化为不同的元素名称。如果是这种情况,那么XmlSerializer确实可以使用 XML 类型名称作为元素名称 —— 但前提是它可以静态地确定属性类型由于存在多个属性而实际上是多态的。因此,以下类将生成您需要的 XML: [XmlElement(typeof(TDerived))]

[XmlType("Outer_X")]
public class Outer
{
    public Outer()
    {
        this.InnerItem = new InnerX();
    }

    [XmlElement(typeof(InnerX))]
    [XmlElement(typeof(Inner))] // Necessary to inform the serializer of polymorphism even though Inner is abstract.
    public Inner InnerItem { get; set; }
}

public abstract class Inner
{
}

[XmlType("Inner_X")]
public class InnerX : Inner
{
}
Run Code Online (Sandbox Code Playgroud)