.net 如何强制使用xsi:type属性?

.net 如何强制使用xsi:type属性?,.net,xml-serialization,.net,Xml Serialization,如何强制.NET的XmlSerializer向类型为的成员/节点添加xsi:type=“FooClass” 该场景是当前发布的应用程序,在v.1中: FooClass继承FooBaseClass FooPropertyA在FooBaseClass上 FooPropertyB在FooClass上 FooBaseClass用[XmlInclude(typeof(FooClass))]修饰 BazClass具有FooBaseClass类型的成员Foo 所有的Baz.Foo集合都是一个FooClass

如何强制.NET的XmlSerializer向类型为
的成员/节点添加xsi:type=“FooClass”

该场景是当前发布的应用程序,在v.1中:

  • FooClass继承FooBaseClass
  • FooPropertyA在FooBaseClass上
  • FooPropertyB在FooClass上
  • FooBaseClass用[XmlInclude(typeof(FooClass))]修饰
  • BazClass具有FooBaseClass类型的成员Foo
  • 所有的Baz.Foo集合都是一个FooClass实例
  • Foo的所有用法都需要FooPropertyB(以及FooClass实例与FooBaseClass)
目标:完全删除FooBaseClass,将FooBaseClass的成员推到FooClass中,同时保持向后序列化兼容性

问题:然后我丢失了Baz.Foo序列化上的xsi:type=“FooClass”属性。

换句话说,的XmlSerializer.Serialize输出

public class BazClass
{
    public BazClass()
    {
        Foo = new FooClass { A = 5, B = "Hello" };
    }
    public FooClass Foo { get; set; }
}

public class FooClass
{
    public int FooPropertyA { get; set; }
    public string FooPropertyB { get; set; }
}
需要

<Baz>
    <Foo xsi:type="FooClass">
        <FooPropertyA>Hello</FooPropertyA>
        <FooPropertyB>5</FooPropertyB>
    </Foo>
</Baz>
我认为简单的答案是,如果不实现I(Xml)可序列化或编写自定义序列化代码,您就不能这样做,至少不能这样做。然而,我愿意接受好的建议。同时,我已经在下面实现了一个解决方法,我希望有更优雅的东西,或者至少可以让我以某种方式完全删除FooBaseClass

BazClass
{
    [XmlElement("Foo")]
    public FooBaseClass XmlFoo { get { return Foo; } set { Foo = (StartPicture)value; } }

    [XmlIgnore]
    public FooClass Foo { get; set; }
}    

FooClass : FooBaseClass
{
    public int FooPropertyB { get; set; }
    public string FooPropertyA { get; set; }
}

[XmlInclude("FooClass")]
FooBaseClass
{
}

我在制作以下内容时没有遇到任何问题:

<?xml version="1.0" encoding="utf-8"?>
<BazClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Foo xsi:type="FooClass">
        <FooPropertyA>Hello</FooPropertyA>
        <FooPropertyB>5</FooPropertyB>
    </Foo>
</BazClass>
(注意,
XmlType
属性被注释掉了。我想看看如果指定了名称空间会发生什么情况)


请显示您使用的代码及其生成的XML。

我在生成以下内容时没有遇到任何问题:

<?xml version="1.0" encoding="utf-8"?>
<BazClass xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
   xmlns:xsd="http://www.w3.org/2001/XMLSchema">
    <Foo xsi:type="FooClass">
        <FooPropertyA>Hello</FooPropertyA>
        <FooPropertyB>5</FooPropertyB>
    </Foo>
</BazClass>
(注意,
XmlType
属性被注释掉了。我想看看如果指定了名称空间会发生什么情况)


请显示您使用的代码及其生成的XML。

XmlSerializer
有时可能非常愚蠢和简单,这在本例中对您有利。只需手动将其放在那里:

public class FooClass
{
    public int FooPropertyA { get; set; }
    public string FooPropertyB { get; set; }

    [XmlAttribute("type", Namespace="http://www.w3.org/2001/XMLSchema-instance")]
    public string XsiType
    {
        get { return "Foo"; }
        set { }
    }
}

XmlSerializer
有时可能非常愚蠢和直接,这在本例中对您有利。只需手动将其放在那里:

public class FooClass
{
    public int FooPropertyA { get; set; }
    public string FooPropertyB { get; set; }

    [XmlAttribute("type", Namespace="http://www.w3.org/2001/XMLSchema-instance")]
    public string XsiType
    {
        get { return "Foo"; }
        set { }
    }
}

要支持在其他名称空间中继承类型,您需要使用与Pavel Minaev建议的类似的解决方案,但使用XmlQualifiedName typed属性而不是string,例如

using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Test
{
    /// <summary>
    /// Base class which is XML serializable and extensible.
    /// </summary>
    [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
    public abstract class BaseClassInOtherNamespace
    {
        /// <summary>
        /// Name of the XML element 
        /// </summary>
        public const string XmlRootName = "Base";

        /// <summary>
        /// XML namespace in which this type is defined.
        /// </summary>
        public const string XmlRootNamespace = "urn:base";

        /// <summary>
        /// Creates an instance which serializes as the correct inherited XML type.
        /// </summary>
        protected BaseClassInOtherNamespace(XmlQualifiedName xsiType)
        {
            XsiType = xsiType;
        }

        /// <summary>
        /// XML type for serialization.
        /// </summary>
        [XmlAttribute("type", Namespace = XmlSchema.InstanceNamespace)]
        public XmlQualifiedName XsiType { get; set; }

        /// <summary>
        /// Some base property.
        /// </summary>
        public int BaseProperty { get; set; }
    }

    /// <summary>
    /// Inheriting class extending the base class, created in a different XML namespace.
    /// </summary>
    [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
    [XmlType(XmlTypeName, Namespace = XmlTypeNamespace)]
    public class InheritingClass : BaseClassInOtherNamespace
    {
        /// <summary>
        /// Name of the XML element 
        /// </summary>
        public const string XmlTypeName = "Inheriting";

        /// <summary>
        /// XML namespace in which this type is defined.
        /// </summary>
        public const string XmlTypeNamespace = "urn:other";

        /// <summary>
        /// Creates an instance.
        /// </summary>
        public InheritingClass() : base(new XmlQualifiedName(XmlTypeName, XmlTypeNamespace))
        {
        }

        /// <summary>
        /// Some new property in a different (inheriting) namespace.
        /// </summary>
        public int InheritingProperty { get; set; }
    }
}
使用System.Xml;
使用System.Xml.Schema;
使用System.Xml.Serialization;
名称空间测试
{
/// 
///基类,它是XML可序列化和可扩展的。
/// 
[XmlRoot(XmlRootName,Namespace=XmlRootNamespace)]
公共抽象类BaseClassionInternamespace
{
/// 
///XML元素的名称
/// 
公共常量字符串XmlRootName=“Base”;
/// 
///定义此类型的XML命名空间。
/// 
公共常量字符串XmlRootNamespace=“urn:base”;
/// 
///创建一个实例,该实例序列化为正确的继承XML类型。
/// 
受保护的BaseClassInOtherNamespace(XmlQualifiedName xsiType)
{
XsiType=XsiType;
}
/// 
///用于序列化的XML类型。
/// 
[XmlAttribute(“类型”,命名空间=XmlSchema.InstanceNamespace)]
公共XmlQualifiedName XsiType{get;set;}
/// 
///一些基本属性。
/// 
公共int BaseProperty{get;set;}
}
/// 
///继承扩展基类的类,该基类在不同的XML命名空间中创建。
/// 
[XmlRoot(XmlRootName,Namespace=XmlRootNamespace)]
[XmlType(XmlTypeName,Namespace=XmlTypeNamespace)]
公共类继承类:BaseClassNotherNamespace
{
/// 
///XML元素的名称
/// 
公共常量字符串XmlTypeName=“继承”;
/// 
///定义此类型的XML命名空间。
/// 
public const string XmlTypeNamespace=“urn:other”;
/// 
///创建一个实例。
/// 
public InheritingClass():base(新的XmlQualifiedName(XmlTypeName,XmlTypeNamespace))
{
}
/// 
///其他(继承)命名空间中的某些新属性。
/// 
公共int继承属性{get;set;}
}
}
将按以下方式正确序列化(和反序列化):

<Base xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:q1="urn:other" xsi:type="q1:Inheriting" xmlns="urn:base">
  <BaseProperty>0</BaseProperty>
  <q1:InheritingProperty>0</q1:InheritingProperty>
</Base>

0
0
这满足了真正可扩展的多态XML类型的要求,即基类可以在任何地方使用,以后的附加组件可以在.NET和XSD验证中正确分配、序列化和反序列化


进一步说,您还可以使用XmlNamespaceDeclarationsAttribute添加XmlSerializerNamespaces属性,以指定首选前缀并删除任何不需要的名称空间,例如xmlns:xsd(我们只使用xmlns:xsi)甚至是非继承XML序列化类的XSI名称空间。

要支持其他名称空间中类型的继承,您需要使用与Pavel Minaev建议的类似的解决方案,但使用XmlQualifiedName类型属性而不是字符串,例如

using System.Xml;
using System.Xml.Schema;
using System.Xml.Serialization;

namespace Test
{
    /// <summary>
    /// Base class which is XML serializable and extensible.
    /// </summary>
    [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
    public abstract class BaseClassInOtherNamespace
    {
        /// <summary>
        /// Name of the XML element 
        /// </summary>
        public const string XmlRootName = "Base";

        /// <summary>
        /// XML namespace in which this type is defined.
        /// </summary>
        public const string XmlRootNamespace = "urn:base";

        /// <summary>
        /// Creates an instance which serializes as the correct inherited XML type.
        /// </summary>
        protected BaseClassInOtherNamespace(XmlQualifiedName xsiType)
        {
            XsiType = xsiType;
        }

        /// <summary>
        /// XML type for serialization.
        /// </summary>
        [XmlAttribute("type", Namespace = XmlSchema.InstanceNamespace)]
        public XmlQualifiedName XsiType { get; set; }

        /// <summary>
        /// Some base property.
        /// </summary>
        public int BaseProperty { get; set; }
    }

    /// <summary>
    /// Inheriting class extending the base class, created in a different XML namespace.
    /// </summary>
    [XmlRoot(XmlRootName, Namespace = XmlRootNamespace)]
    [XmlType(XmlTypeName, Namespace = XmlTypeNamespace)]
    public class InheritingClass : BaseClassInOtherNamespace
    {
        /// <summary>
        /// Name of the XML element 
        /// </summary>
        public const string XmlTypeName = "Inheriting";

        /// <summary>
        /// XML namespace in which this type is defined.
        /// </summary>
        public const string XmlTypeNamespace = "urn:other";

        /// <summary>
        /// Creates an instance.
        /// </summary>
        public InheritingClass() : base(new XmlQualifiedName(XmlTypeName, XmlTypeNamespace))
        {
        }

        /// <summary>
        /// Some new property in a different (inheriting) namespace.
        /// </summary>
        public int InheritingProperty { get; set; }
    }
}
使用System.Xml;
使用System.Xml.Schema;
使用System.Xml.Serialization;
名称空间测试
{
/// 
///基类,它是XML可序列化和可扩展的。
/// 
[XmlRoot(XmlRootName,Namespace=XmlRootNamespace)]
公共抽象类BaseClassionInternamespace
{
/// 
///XML元素的名称
/// 
公共常量字符串XmlRootName=“Base”;
/// 
///定义此类型的XML命名空间。
/// 
公共常量字符串XmlRootNamespace=“urn:base”;
/// 
///创建一个实例,该实例序列化为正确的继承XML类型。
/// 
受保护的BaseClassInOtherNamespace(XmlQualifiedName xsiType)
{
XsiType=XsiType;
}
/// 
///用于序列化的XML类型。
/// 
[XmlA