【问题标题】:C# Xml-Serialization of abstract base type into derived type - which TypeName property definition wins?C# Xml-将抽象基类型序列化为派生类型 - 哪个 TypeName 属性定义获胜?
【发布时间】:2014-09-03 17:31:42
【问题描述】:

我的场景:

我有一个对象,我定义了一个用 XmlElement 标记修饰的属性并具有我定义的类型,其中一些类型为抽象类型,并设置为相应的派生类型。我想使用 XmlSerializer 将整个对象序列化为 XML,并且所有抽象的属性都应该序列化为 TypeName 设置为派生类型的 TypeName 的元素。

这是对象结构的示例:

[XmlType(TypeName = "MAINOBJECT")]
public class MainObject
{
    [XmlElement(Type = typeof(DerivedClass))]
    public BaseClass TheBase { get; set; }
}

[XmlInclude(typeof(DerivedClass))]
public abstract class BaseClass
{
    [XmlAttribute("AnAttribute")]
    public string AnAttribute { get; set; }

    [XmlElement("ANELEMENT")]
    public string AnElement { get; set; }

}

[XmlType(TypeName = "DERIVEDCLASS")]
public class DerivedClass : BaseClass
{
    [XmlElement("ANOTHERELEMENT")]
    public string AnotherElement { get; set; }

}

但是请注意,当我创建一个新的 MainObject 实例,填充它的属性并对其进行序列化时,生成的 XML 如下所示:

<MAINOBJECT>
    <BaseClass AnAttribute="">
            <ANELEMENT/>
            <ANOTHERELEMENT/>
    </BaseClass>
</MAINOBJECT>

我想要的是这个:

<MAINOBJECT>
    <DERIVEDCLASS AnAttribute="">
            <ANELEMENT/>
            <ANOTHERELEMENT/>
    </DERIVEDCLASS>
</MAINOBJECT>

任何线索我在这里做错了什么?

【问题讨论】:

    标签: c# xml-serialization derived-class abstract-base-class


    【解决方案1】:

    将XmlElement名称添加到MainObject中的TheBase,如下:

    [XmlType(TypeName = "MAINOBJECT")]
    public class MainObject
    {
        [XmlElement("DERIVEDCLASS", Type = typeof(DerivedClass))]
        public BaseClass TheBase { get; set; }
    }
    

    【讨论】:

    • 了解我不想硬编码元素的名称,我希望它动态选择从我分配给 TheBase 的 BaseClass 派生的任何类作为其 TypeName。
    • 序列化不是这样工作的,因为如果有多个相同类型的属性,就无法区分它们。例如,public BaseClass TheBasepublic BaseClass TheBase2
    • 在这种情况下,第一个默认为“TheBase”,第二个默认为“TheBase2”,除非您指定了 TypeName。但是,我为分配给 TheBase 的派生类型指定了类型名称。我希望它在序列化时使用派生类型的 TypeName。我想错了吗?
    • 是的,它类似于string 属性,名称为string。例如,如果您有public string TheBase,您希望序列化名称是&lt;string&gt; 还是&lt;TheBase&gt;
    • 嗯,这很有效,哈哈。我至少应该在最初解雇它之前尝试过它,非常感谢:) “这个”是指 [XmlElement("DERIVEDCLASS", Type = typeof(DerivedClass))] public BaseClass TheBase { get;放; }
    【解决方案2】:

    在我看来,最好的解决方案是实现IXmlSerializable 接口,这样您就可以完全控制对象的序列化方式。当然,这需要更多的工作,但是如果您有类似这样的要求有些与众不同,那么您可能还会遇到更多的怪癖,标准 XmlSerializer 将无法为您工作。

    这里有很好的教程:How to Implement IXmlSerializable Correctly

    另外,这里有一些很好的信息:Proper way to implement IXmlSerializable?

    【讨论】:

    • 我现在将使用 IXmlSerializable 进行调查,如果我可以让我的实现正常工作,我会将其标记为正确答案。谢谢!
    【解决方案3】:

    也许不是最好的解决方案,但是:

    class Program
        {
            static void Main(string[] args)
            {
                XmlAttributes attrs = new XmlAttributes();
    
                XmlElementAttribute attr = new XmlElementAttribute();
                attr.ElementName = "DerivedClass";
                attr.Type = typeof(DerivedClass);
    
                attrs.XmlElements.Add(attr);
    
                XmlAttributeOverrides attrOverrides = new XmlAttributeOverrides();
    
                attrOverrides.Add(typeof(MainObject), "TheBase", attrs);
    
                XmlSerializer s = new XmlSerializer(typeof(MainObject), attrOverrides);
    
                StringWriter writer = new StringWriter();
    
                MainObject mo = new MainObject { TheBase = new DerivedClass { AnAttribute = "AnAttribute", AnElement = "AnElement", AnotherElement = "AotherElement" } };
    
                s.Serialize(writer, mo);
                Console.Write(writer.ToString());
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-25
      • 1970-01-01
      • 1970-01-01
      • 2018-11-19
      • 1970-01-01
      • 1970-01-01
      • 2011-01-11
      相关资源
      最近更新 更多