.net 如何强制使用xsi:type属性?
如何强制.NET的XmlSerializer向类型为.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
的成员/节点添加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