如何强制.NET的XmlSerializer将xsi:type =“FooClass”添加到FooClass类型的成员/节点?
该方案是当前发布的应用程序,其中第1版:
> FooClass继承FooBaseClass
> FooPropertyA在FooBaseClass上
> FooPropertyB在FooClass上
> FooBaseClass用[XmlInclude(typeof(FooClass))]装饰
> BazClass有FooBaseClass类型的成员Foo
>所有Baz.Foo集都属于FooClass实例
> Baz.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>
删除FooBasClass很简单,但是XmlSerializer不再在Baz / Foo上放置xsi:type =“FooClass”,因此v.1 XmlSerializer.Deserialize实例化FooBaseClass实例,而不是设置FooPropertyB,并将其分配给父级的Foo属性巴兹实例.因此,任何检查Baz.Foo是FooClass还是直接转换的代码都会失败.
public class BazClass { public BazClass() { Foo = new FooClass { A = 5,B = "Hello" }; } public FooBaseClass Foo { get; set; } } public class FooClass : FooBaseClass { public string FooPropertyB { get; set; } } [XmlInclude(typeof(FooClass))] public class FooBaseClass { public int FooPropertyA { get; set; } }
我认为简短的答案是你不能 – 至少没有实现I(Xml)Serializable或编写自定义序列化代码.但是,我愿意接受好的建议.同时我已经在下面实现了一个解决方法hack,并希望有更优雅的东西,或者至少允许我以某种方式完全删除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 { }
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 { } } }