How can I force the use of an xsi:type attribute?

后端 未结 3 876
忘掉有多难
忘掉有多难 2020-12-20 07:44

How can I force .NET\'s XmlSerializer to add an xsi:type=\"FooClass\" to a member/node of type FooClass?

The scenario

3条回答
  •  孤城傲影
    2020-12-20 08:35

    To support inheritance of types in other namespaces you need to use a solution similar to what Pavel Minaev suggested but with the XmlQualifiedName typed property instead of string, e.g.

    using System.Xml;
    using System.Xml.Schema;
    using System.Xml.Serialization;
    
    namespace Test
    {
        /// 
        /// Base class which is XML serializable and extensible.
        /// 
        [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
        public abstract class BaseClassInOtherNamespace
        {
            /// 
            /// Name of the XML element 
            /// 
            public const string XmlRootName = "Base";
    
            /// 
            /// XML namespace in which this type is defined.
            /// 
            public const string XmlRootNamespace = "urn:base";
    
            /// 
            /// Creates an instance which serializes as the correct inherited XML type.
            /// 
            protected BaseClassInOtherNamespace(XmlQualifiedName xsiType)
            {
                XsiType = xsiType;
            }
    
            /// 
            /// XML type for serialization.
            /// 
            [XmlAttribute("type", Namespace = XmlSchema.InstanceNamespace)]
            public XmlQualifiedName XsiType { get; set; }
    
            /// 
            /// Some base property.
            /// 
            public int BaseProperty { get; set; }
        }
    
        /// 
        /// Inheriting class extending the base class, created in a different XML namespace.
        /// 
        [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
        [XmlType(XmlTypeName, Namespace = XmlTypeNamespace)]
        public class InheritingClass : BaseClassInOtherNamespace
        {
            /// 
            /// Name of the XML element 
            /// 
            public const string XmlTypeName = "Inheriting";
    
            /// 
            /// XML namespace in which this type is defined.
            /// 
            public const string XmlTypeNamespace = "urn:other";
    
            /// 
            /// Creates an instance.
            /// 
            public InheritingClass() : base(new XmlQualifiedName(XmlTypeName, XmlTypeNamespace))
            {
            }
    
            /// 
            /// Some new property in a different (inheriting) namespace.
            /// 
            public int InheritingProperty { get; set; }
        }
    }
    

    Will serialize (and de-serialize) correctly as:

    
      0
      0
    
    

    This satisfies the requirement of truly extensible polymorphic XML types, i.e. the base class can be used anywhere and later add-ons can be assigned, serialized and de-serialized correctly in both .NET and with XSD validation.

    Taking it further, you can also add a XmlSerializerNamespaces property with the XmlNamespaceDeclarationsAttribute to specify preferred prefixes and remove any unwanted namespaces, such as the xmlns:xsd (we only use xmlns:xsi) or even the XSI namespace for your non-inheriting XML serialized classes.

提交回复
热议问题